Skip to content

feat(studio): add studio_inspect, so an agent reads before it writes - #3517

Draft
miguel-heygen wants to merge 1 commit into
feat/studio-webmcp-framefrom
feat/studio-webmcp-inspect
Draft

feat(studio): add studio_inspect, so an agent reads before it writes#3517
miguel-heygen wants to merge 1 commit into
feat/studio-webmcp-framefrom
feat/studio-webmcp-inspect

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

studio_inspect returns everything about one element in a single call: resolved styles, text fields, box, data attributes, GSAP animations, and what the element will and will not accept.

Also extracts the shared WebMCP test fixtures into webmcpTestUtils.ts, which removes the duplication that was accumulating across the tool test files and the as HTMLElement casts that came with it.

Stacked on #3516.

Why

The point is to prevent a failed write, not to satisfy curiosity. can.reasonIfDisabled comes through verbatim from Studio's own capabilities, so an agent that reads first should never attempt an edit the element would refuse. That matters more here than in a normal API, because a refused write in Studio is often silent.

How

Three things it refuses to get wrong:

Animations are reported only for the current selection, because that is the only element Studio parses them for. Attributing them to any other element would be reporting the wrong element's motion, which is worse than reporting none. When a handle names something else the list is empty and animationEditingBlocked says why.

animationEditingBlocked also carries the two states where animation editing is off entirely, multiple timelines and an unsupported timeline pattern. Both live on the selection context. Learning them from a read costs one call; learning them from a failed write costs a retry loop.

Inspecting does not change the selection. It is a read, and stealing the human's selection would be a side effect they did not ask for. There is a test asserting applySelection is never called.

Nothing selected and no handle given is a failure, not an empty result. An empty result would assert "this element has nothing", which is a different and false claim.

Test plan

  • Unit tests added/updated
  • Manual testing performed
  • Documentation updated (if applicable)

8 tests in inspectTools.test.ts, and the whole WebMCP suite re-run after the fixture extraction:

  • Resolved styles come back, not authored ones.
  • Capabilities and reasonIfDisabled pass through verbatim.
  • Animations list for the current selection, with ease and id.
  • Both animationEditingBlocked reasons are asserted separately.
  • A handle naming a different element gets an empty animation list and a reason, rather than the selection's animations.
  • Inspecting a handle does not call applySelection.
  • No selection and no handle is a failure with a hint, not an empty result.
  • Unknown handle and unmounted preview produce distinct reasons.

WebMCP suite 78 passing. Full package suite 4563 passing across 411 files. bunx tsc --noEmit clean, bunx oxlint clean, bunx fallow audit --fail-on-issues clean.

Still no browser verification anywhere in this stack; that is the final unit.

Everything about one element in one call: resolved styles, text fields, box,
data attributes, GSAP animations, and what the element will and will not
accept.

The point is to prevent a failed write rather than to satisfy curiosity.
`can.reasonIfDisabled` is passed through verbatim from Studio's own
capabilities, so an agent that reads first should never attempt an edit the
element would refuse.

Three things it refuses to get wrong:

Animations are reported ONLY for the current selection, because that is the
only element Studio parses them for. Attributing them to any other element
would be reporting the wrong element's motion, which is worse than reporting
none. When a handle names something else the field is empty and
`animationEditingBlocked` says why.

`animationEditingBlocked` also carries the two states where animation editing
is off entirely, multiple timelines and an unsupported timeline pattern. Both
live on the selection context. Learning them from a read costs one call;
learning them from a failed write costs a retry loop.

Inspecting a handle does NOT change what is selected. It is a read, and
stealing the human's selection would be a side effect they did not ask for.
There is a test asserting `applySelection` is never called.

Nothing selected and no handle given is a failure, not an empty result. An
empty result would assert "this element has nothing", which is a different and
false claim.
@miguel-heygen
miguel-heygen force-pushed the feat/studio-webmcp-frame branch from d7ba77c to 57c9bb0 Compare August 27, 2026 04:48
@miguel-heygen
miguel-heygen force-pushed the feat/studio-webmcp-inspect branch from bc098b8 to 1478adf Compare August 27, 2026 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant