Skip to content

Tool backend protocol

The runtime calls the backend of an http or grpc ToolRegistry handler with the contracts below. Handler fields are in the ToolRegistry reference.

AspectBehaviour
URLhttpConfig.endpoint, or httpConfig.urlTemplate when set
MethodhttpConfig.method, default POST
BodyFor POST, PUT and PATCH, the tool-call arguments as JSON, verbatim. No body is sent when the arguments are empty (null or {})
Query stringFor every other method (GET, DELETE, and so on), each top-level argument becomes a query parameter, formatted with Go %v. No body is sent
Content-TypeSet only when a body is sent. Value: httpConfig.contentType, default application/json

The shaping fields urlTemplate, queryParams, headerParams, staticQuery, staticBody and bodyMapping change this table. See Advanced HTTP tools.

The runtime sets each header below when it has a value for it.

HeaderValue
x-omnia-tool-nameThe tool name
x-omnia-tool-registryThe handler name
x-omnia-agent-nameThe agent name
x-omnia-session-idThe session ID. Sent for A2A and function-invocation calls, not for WebSocket conversations
x-omnia-delegationA delegation JWT, when the handler sets delegation.enabled and the runtime has a delegation endpoint configured. See Delegation tokens
x-omnia-param-<Name>One header per scalar (string, number or boolean) argument, with the argument name in PascalCase. A value that is not a valid header value, such as one containing a newline, is skipped
AuthorizationThe credential from the handler’s auth stanza

The runtime also sends the caller-identity headers below. Each is sent only when it has a non-empty value.

HeaderValue
x-omnia-namespaceThe agent’s namespace
x-omnia-request-idThe per-request correlation ID
x-omnia-user-idThe end user’s ID, pseudonymised
x-omnia-subject-idThe pseudonymised ID of the token holder. Absent when the token holder is the end user
x-omnia-user-emailThe end user’s email address
x-omnia-providerThe spec.type of the agent’s Provider, such as claude or openai
x-omnia-modelThe agent’s model. Absent when the Provider sets none
x-omnia-originThe auth validator that admitted the request
x-omnia-workspaceThe workspace of the token, else the agent’s workspace
x-omnia-claim-<name>One header per claim in the admitting validator’s claim map

The inbound Authorization token is never forwarded.

Headers from httpConfig.headers, headersFromSecret and ToolPolicy broker-injected headers are also sent. On a name collision, the later source wins: headers, then auth, then headersFromSecret, then the Omnia headers above, then broker-injected headers, then headers built from headerParams.

Backend responseResult for the model
2xx, body is valid JSONThe body, after redact and then responseMapping
2xx, body is not valid JSON (including an empty body){"result": "<body as a string>"}. redact and responseMapping do not apply
Any other statusA tool error, HTTP <status>: <body>, with the body truncated to 512 bytes plus .... The body is not parsed

The runtime reads at most 10 MB of a response body. Each attempt is bound by the handler’s timeout (default 30s). Retries happen only when httpConfig.retryPolicy is set.

Each runtime pod keeps a circuit breaker per tool. It opens when at least half of the tool’s calls in a rolling 60-second window fail, once the window holds at least 20 calls, or after 10 consecutive failures within the window. While open, calls fail at once instead of waiting for the backend. After 10 seconds it lets 5 trial calls through and closes again if they all succeed. A 4xx response does not count as a failure (the backend answered; the request was wrong), and neither does a call abandoned because its conversation ended. A tool called less than about once every 6 seconds never collects 10 failures within the window, so a dead one is not short-circuited: each call waits for its timeout.

A handler with a sandbox block reaches a different sandbox in each conversation, so its breaker is per conversation’s claim, not per tool: one conversation’s failing sandbox does not refuse other conversations’ calls. The facade opens one stream to the runtime per message, and a conversation’s breakers are dropped when that stream ends, so a claim’s breaker only opens on 10 failed calls within one message and starts closed at the next. What keeps a dead sandbox cheap across messages is the reachability check: a claim already proven reachable in the conversation is dialled once before a call, not retried, so a call to a dead one fails at once.

The service is omnia.tools.v1.ToolService, defined in api/proto/tools/v1/tools.proto. The generated Go package is github.com/altairalabs/omnia/pkg/tools/v1.

service ToolService {
rpc Execute(ToolRequest) returns (ToolResponse);
rpc ListTools(ListToolsRequest) returns (ListToolsResponse);
}
MessageFieldTypeNumber
ToolRequesttool_namestring1
arguments_jsonstring (JSON)2
metadatamap<string, string>3
ToolResponseresult_jsonstring (JSON)1
is_errorbool2
error_messagestring3
ListToolsRequestnone
ListToolsResponsetoolsrepeated ToolInfo1
ToolInfonamestring1
descriptionstring2
input_schemastring (JSON Schema)3

The runtime calls /omnia.tools.v1.ToolService/Execute with tool_name and arguments_json, the arguments as an opaque JSON string. It does not populate metadata.

Backend responseResult for the model
is_error false, result_json setresult_json
is_error false, result_json emptynull
is_error trueA tool error, tool error: <error_message>

The runtime sends these headers as lowercase gRPC metadata keys: the caller-identity headers, x-omnia-tool-name, x-omnia-tool-registry, x-omnia-agent-name, x-omnia-session-id and x-omnia-delegation, with authorization carrying the handler’s auth credential. ToolPolicy broker-injected headers override these on a name collision. A gRPC backend receives no x-omnia-param-<Name> metadata, because the runtime passes no arguments to the metadata builder.

The runtime calls /omnia.tools.v1.ToolService/ListTools only for a grpc handler that has no tool definition, and registers the tools it returns. The ToolRegistry controller rejects a grpc handler without tool, so a backend reached through a ToolRegistry needs only Execute.

grpcConfig.tls defaults to false, which dials plaintext. tlsCertPath takes effect only together with tlsKeyPath. See the gRPC handler options.