Skip to content

Service browser observation (AGNT2-621) ​

The API host sends JSON-RPC agentfy/browserView with { requestId } on the existing authenticated tool channel. This is not an MCP tool. The host has a separate bounded observation waiter map (8 per connection, 8-second deadline); worker dispatch never touches tool routing, the session clock or activity logs. The API request/reply wait is bounded to nine seconds and 128 pending per replica.

  1. After team/organization authorization and finding an existing running session, the requesting API generates a random 256-bit request id and an ephemeral P-256 ECDH key pair. Redis retains only { sessionId, publicKey } for ten seconds. Private keys and frames are never written to Redis keys.
  2. A Redis pub/sub request reaches all API replicas in the deployment namespace; only the replica with that session's socket forwards it. The response returns to the requesting replica's private random reply topic. Topics explicitly include the Redis DB number because pub/sub itself ignores DB selection.
  3. The worker relays only requestId to the isolated broker's /observe socket path. The broker independently redeems it at POST /v1/internal/worker-observations/consume using its browser-broker pass. An ordinary worker pass is refused. Atomic consumption checks the session binding before deletion; replay, expiry and a different session cannot consume.
  4. The API returns the destination public key directly to the broker over its authenticated API connection. The shell cannot choose/replace this key or receive a raw capture from /observe. The broker takes a read-only capture from the shared Chromium profile without joining the tool operation queue.
  5. The broker generates its own ephemeral P-256 pair, derives 32 bytes with HKDF-SHA256 (salt: UTF-8 request id; info: agentfy-browser-view-v1), and encrypts the JSON page (including URL/title, or null) with AES-256-GCM and a random 12-byte IV. AAD is the UTF-8 request id. The result is { envelope: { publicKey, iv, tag, ciphertext } }; the first three fields are hex, ciphertext is base64. Only the requesting API can decrypt. Altered keys, ciphertext, tags or request binding fail closed.
  6. The API validates the decrypted shape, JPEG marker and size, checks session and authorization again, then returns the page to the human. Socket loss, timeout or unsupported images are unavailable, not stopped. Polling cannot prolong the worker's life on either end.

The broker’s private profile and credential remain outside the ordinary worker container. An agent can interfere with its own shared IPC socket and cause a failed view, but cannot redeem its viewing capability with the worker pass or recover the plaintext frame from the encrypted reply. A malicious site still knows what that site renders; this feature does not change that trust boundary.

The capture uses Target.getTargetInfo, Page.getLayoutMetrics, and Page.captureScreenshot with JPEG quality and scaled clip. It never calls bringToFront, modifies the DOM, disables script execution, or persists an image. See the CDP Page specification and Node crypto documentation.