Remote Tool Protocol

Implement or consume the shared Ansight tool discovery, catalog, call, batch, response, and compressed-payload protocol.

The local host player and CLI use one remote-tool protocol across the .NET, Android, iOS, React Native, Flutter, and Cordova/Capacitor SDKs. The native runtime carries the protocol over the authenticated live WebSocket session; cross-platform SDKs use the same native bridge and wire contract.

Applications normally work through their SDK’s registration APIs rather than constructing these messages. This page is the compatibility contract for host, SDK, bridge, and tooling authors.

Envelope

Every message is a JSON object with the following fields:

FieldMeaning
typeMessage discriminator: tool.query, tool.catalog, tool.call, tool.batch, tool.result, tool.batch.result, or tool.error.
idIdentifier for this message.
replyToRequest id being answered; present on responses.
sessionIdLive session associated with the request or response.
sentAtUTC timestamp for the envelope.
capabilitytool.exec.
payloadMessage-specific JSON payload, or an encoded-payload wrapper described below.

Use replyTo, not a response naming convention, to correlate a response with its request.

Catalog Discovery

Request the current compact index with tool.query. When a caller already has an index, pass both revisions:

{
  "type": "tool.query",
  "id": "tool_query_1",
  "sessionId": "session_1",
  "sentAt": "2026-08-25T00:00:00Z",
  "capability": "tool.exec",
  "payload": {
    "detail": "index",
    "ifRevision": "sha256:known-catalog-revision",
    "ifAvailabilityRevision": "sha256:known-availability-revision"
  }
}

The SDK responds with tool.catalog using schema ansight.tool-catalog.v3:

{
  "type": "tool.catalog",
  "id": "tool_query_1.response",
  "replyTo": "tool_query_1",
  "sessionId": "session_1",
  "sentAt": "2026-08-25T00:00:00.050Z",
  "capability": "tool.exec",
  "payload": {
    "schema": "ansight.tool-catalog.v3",
    "revision": "sha256:current-catalog-revision",
    "availabilityRevision": "sha256:current-availability-revision",
    "evaluatedAtUtc": "2026-08-25T00:00:00.050Z",
    "detail": "index",
    "tools": [
      {
        "id": "ui.perform_action",
        "name": "Perform UI Action",
        "description": "Performs a generic action against a current snapshot-scoped UI node.",
        "category": "ui",
        "policy": "write",
        "definitionRevision": "sha256:tool-definition-revision",
        "prerequisiteToolIds": ["ui.query_nodes"]
      }
    ],
    "count": 1,
    "totalCount": 84,
    "categories": { "ui": 12 }
  }
}

revision is a deterministic SHA-256 value derived from the catalog schema, guard, visible tool ids, and each tool’s definitionRevision. The separate availabilityRevision changes when runtime executability changes.

When both supplied revisions match, the payload is exactly schema, revision, and unchanged: true. When only availability changed, the response also includes the new availabilityRevision, one evaluatedAtUtc, and a changes object containing only non-default states. Treat changes as a replacement snapshot: omitted tools are available and executable.

Index entries omit schemas. Request selected definitions with detail: "definitions" and ids: [...]; cache each response by definitionRevision. A request without detail remains compatible and returns full definitions. ids, query, feature, policy, executableOnly, and limit/maxResults are applied in the SDK before serialization.

JSON argument encoding, available/executable state, empty keywords, and additionalProperties: false are protocol defaults and are omitted, as are unchanged: false and the default detail: "full". Definition projections omit index-level availability, timestamp, category, and total-count metadata. A flattened-string tool declares argumentEncoding: "flattened-string". Unavailable tools carry a compact runtime object with available: false and optional code, reason, requiredState, remediation, and retryable. Availability is evaluated again immediately before execution.

Calls and Results

Invoke one tool with tool.call:

{
  "type": "tool.call",
  "id": "tool_call_1",
  "sessionId": "session_1",
  "sentAt": "2026-08-25T00:01:00Z",
  "capability": "tool.exec",
  "payload": {
    "toolId": "ui.perform_action",
    "arguments": {
      "reference": {
        "source": "native",
        "snapshotId": "native:42:example",
        "revision": 42,
        "nodeId": "root.0.save"
      },
      "action": "tap"
    },
    "after": {
      "include": ["visualTree", "screenshot"],
      "delayMilliseconds": 100
    }
  }
}

arguments must be a JSON object. Native JSON tools receive it without flattening and validate both arguments and results against their published schemas. Older tools that advertise flattened-string remain compatible.

Successful calls return tool.result. Its payload contains toolId, success: true, optional message, result, and optional evidence. Protocol, guard, availability, validation, and execution failures return tool.error; its payload contains stable code, human-readable message, retryable, and optional details.

An after request composes a call with post-call evidence. include accepts visualTree and screenshot, and delayMilliseconds accepts 0 through 2000. Tool-specific visualTreeArguments and screenshotArguments can refine those captures. Large binary artifacts use the separate ASFT (ansight.file-transfer.v1) binary stream and are referenced from the JSON result.

Batches

Use tool.batch to execute between 1 and 32 calls sequentially:

{
  "type": "tool.batch",
  "id": "tool_batch_1",
  "sessionId": "session_1",
  "sentAt": "2026-08-25T00:02:00Z",
  "capability": "tool.exec",
  "payload": {
    "continueOnError": false,
    "calls": [
      {
        "callId": "inspect-save",
        "toolId": "ui.query_nodes",
        "arguments": { "automationId": "save" }
      },
      {
        "callId": "tap-save",
        "toolId": "ui.perform_action",
        "arguments": {
          "reference": {
            "source": "native",
            "snapshotId": "native:42:example",
            "revision": 42,
            "nodeId": "root.0.save"
          },
          "action": "tap"
        },
        "after": { "include": ["visualTree"] }
      }
    ]
  }
}

The tool.batch.result payload preserves input order and reports success, completed, requested, stoppedEarly, and results. Each result includes its zero-based index, optional caller-provided callId, tool outcome, and any post-call evidence. Execution stops after the first invalid or failed call unless continueOnError is true.

Large JSON Payload Encoding

SDK responses may replace payload with a compressed wrapper when its compact JSON representation is at least 32 KiB and gzip plus base64 is smaller than the original. This applies to catalog, result, batch-result, and error responses. Small or incompressible payloads remain ordinary JSON.

{
  "type": "tool.catalog",
  "id": "tool_query_1.response",
  "replyTo": "tool_query_1",
  "sessionId": "session_1",
  "sentAt": "2026-08-25T00:00:00.050Z",
  "capability": "tool.exec",
  "payload": {
    "$ansightEncoding": "gzip-base64-json",
    "contentType": "application/json",
    "originalByteCount": 65536,
    "compressedByteCount": 2048,
    "data": "H4sIAAAAA..."
  }
}

Envelope fields are never compressed by this mechanism. A consumer must inspect the payload before interpreting message-specific fields:

  1. If $ansightEncoding is absent, process payload as ordinary JSON.
  2. For gzip-base64-json, base64-decode data, gunzip the bytes, decode them as UTF-8, and parse the result as the actual JSON payload.
  3. Reject unsupported encodings, missing or invalid base64 data, gzip failures, and invalid decoded JSON as protocol errors.

originalByteCount and compressedByteCount describe the pre-base64 byte counts. They are metadata for diagnostics and bounds checks, not replacement payload lengths. Current resident hosts decode the wrapper before catalog caching, authorization filtering, result normalization, or artifact handling.

Authorization

Tool policy is one ordered value: read < write < critical. Read-only guards permit read, read/write guards permit read and write, and full-access guards permit all three. Use critical for destructive, secret-bearing, or arbitrary code-invoking operations. The paired client’s maxToolPolicy can lower the effective maximum but cannot raise the app’s local guard.

The guard affects both discovery and execution. Callers should discover the catalog before invoking tools, follow the published schemas exactly, and handle guard or runtime availability changes at call time.