#841 taught the LLM node to send camera frames to a vision model, but only for a camera on the same server. A camera on a peer was skipped with a warning, and I filed #860 to fix it “later”, asserting in the PR that:
Supporting it needs an authenticated binary GET against the peer’s
/camera/{id}/snapshot, whichNodeHttpdoesn’t expose today.
That was wrong. NodeHttp.getCameraSnapshot(host, cameraId): ByteArray? has existed the
whole time — it builds the peer’s base URL, applies bearer auth, and returns the bytes.
composeApp already calls it from four places (CameraView, CameraScreen,
ProjectScreen, DiagramScreen). It is in the SDK version krill already pins.
So the limitation I shipped and filed a follow-up for did not exist. The capability was one
call away, and the demo’s own topology — the Sentry LLM node on one server watching nodes
on another — is exactly the case I left broken.
I checked whether NodeHttp exposed what I needed by grepping its private helpers
(baseUrl, withAuth) and the class’s public shape near the node CRUD methods, concluded
“no byte-fetch here”, and stopped. getCameraSnapshot is 250 lines further down the same
file. The consumers were in a module I wasn’t reading (composeApp), so nothing contradicted
me.
The tell I ignored: I was reasoning about what the SDK would need to add, for a capability the UI visibly already had. Krill’s camera views render peer cameras. If the app can show a peer’s frame, the server can fetch one.
ServerNodeManager.readCameraSnapshot(id: NodeIdentity) — resolves the host the same way
findNode does and delegates to NodeHttp.getCameraSnapshot.ServerLLMProcessor.cameraFrameBytes() reads the frame off local disk when the path
resolves here, and fetches it from the owning host when it does not. Null means “no frame”
and the image is omitted — never sent empty.getCameraSnapshot, ByteArray), not
the region of the file you happen to be reading. A public method 250 lines from where you
looked is indistinguishable from one that does not exist, until you look.