Skip to content

Releases: noahkurz/react-native-agent-jet

Release list

v0.11.0

Choose a tag to compare

@noahkurz noahkurz released this 23 Sep 01:52

Three fixes from driving a real Expo app with v0.10.0.

#id targets work as printed

tree prints ids as #11, and both the README and the target description invite you to paste one back — but the comparison was against the bare number, so press "#11" failed with No visible element matches "#11". Only "11" worked.

Now either form matches, across every element tool. Text that merely begins with # ("#1 priority") is still matched as text. Not breaking — bare "11" still works.

A taken port says so

The bind error only reached stderr, so status looked normal and every call blamed useAgentJet() for a server that had never started listening. With two RN apps, or two editors on one app, this is where you land — and the app may well have connected to someone else's server.

status now carries the reason when there is one:

"serverError": "Port 8765 is already in use, so this server is not listening and no app can reach it. Another agent-jet server has it — a second editor, or another app's session. Give this one its own port with AGENT_JET_PORT, and start the app with EXPO_PUBLIC_AGENT_JET_PORT set to the same number."

The same message is the error for any tool call, returned immediately — including calls already waiting when the bind fails. doctor no longer implies all is well when the port is taken, and names the port when nothing connects.

The app can change ports without a source edit

The server read AGENT_JET_PORT; the bridge hardcoded 8765, so resolving a collision meant editing a root layout and remembering to revert it. The bridge now reads EXPO_PUBLIC_AGENT_JET_PORT, which Expo inlines:

AGENT_JET_PORT=8766 …                          # the server
EXPO_PUBLIC_AGENT_JET_PORT=8766 npx expo start # the app

useAgentJet({ url }) still overrides both. Non-Expo apps are unaffected.

If you develop against a linked checkout

Reading that variable makes Expo's Babel preset inject import "expo/virtual/env" into the package's own module. That resolves from node_modules, but not from a bun link checkout outside the app. If you use the setup in docs/local-development.md, update your app's metro.config.js to let the app own every expo subpath, as it already did for react and react-native — the guide has the new version. Normal installs need no change.

Also

207 tests (was 197), each new one confirmed to fail without its fix. Verified on the iOS Simulator and an Android emulator through the packed tarball.

Full changelog: v0.10.0...v0.11.0

v0.10.0

Choose a tag to compare

@noahkurz noahkurz released this 21 Sep 15:09

Cheaper screenshots, correct Android frames, and roughly half the tokens per reply — with the README's cost table now measured rather than estimated.

Screenshots

  • Half the point size by default — a quarter of the image tokens (144 vs 560 on an iPhone 17 Pro Max), still enough for layout, spacing and colour. scale:1 when you need to read rendered text.
  • target crops to one element at full detail with 12pt of context: 8–48 image tokens for a button or a full-width row.
  • Resized in-process with node:zlib — same output and cost on every platform, no sips.
  • Replies drop the timestamped path and say how to convert coordinates: Cropped to #11 Pressable "increment", 80px wide; 1px = 1pt, then add (216,331) for tap/swipe.

Fixes

  • Android frames are now screen points. measureInWindow answers relative to the window, which starts below the status bar unless the app is edge-to-edge; tap, swipe and crops were off by that height. Frames are moved onto the screen at the source, mirroring the inset React Native itself subtracts.
  • reload no longer kills the app in Expo Go on iOS. React Native's reload left the new runtime without Expo's native modules (Cannot find native module 'ExpoAsset'); the bridge now uses Expo's own reload on iOS when present. Android keeps React Native's, which is the one that works there.
  • Crop edges are rounded from point edges, so a fractional device scale cannot shave a pixel off the far side.

Token efficiency (measured with count_tokens against claude-opus-5, demo Home screen)

Call 0.9.0 0.10.0
nav_state 95 22
tree · interactive 301 184
tree (default) 504 382
tree · frames 870 602
screenshot · target (all-in) — 58–107
screenshot (default, all-in) ~1,000–1,600 175

How: shorter tool schemas (the why moved to the playbook, which loads once), whole-point frames, compact JSON, a two-line nav_state without the random route key, and a tree that collapses forwarded wrappers (BottomTabItem → Pressable, TextInput around its host input) and reads Animated(X) as X.

interactive:true now keeps a list row's text — #42 Pressable "#2 qui est esse" [press] instead of Pressable [press] ×N with no way to tell rows apart — so it is finally usable on lists, and press by that text climbs to the row.

Also

  • navState is typed in the protocol; pngWidth (unused outside tests) is gone.
  • 197 tests (was 145); verified end-to-end through the packed tarball in Expo Go on iOS and Android.

Full changelog: 45bdd58...v0.10.0