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.
HTTP handler
Section titled “HTTP handler”Request
Section titled “Request”| Aspect | Behaviour |
|---|---|
| URL | httpConfig.endpoint, or httpConfig.urlTemplate when set |
| Method | httpConfig.method, default POST |
| Body | For POST, PUT and PATCH, the tool-call arguments as JSON, verbatim. No body is sent when the arguments are empty (null or {}) |
| Query string | For 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-Type | Set 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.
Request headers
Section titled “Request headers”The runtime sets each header below when it has a value for it.
| Header | Value |
|---|---|
x-omnia-tool-name | The tool name |
x-omnia-tool-registry | The handler name |
x-omnia-agent-name | The agent name |
x-omnia-session-id | The session ID. Sent for A2A and function-invocation calls, not for WebSocket conversations |
x-omnia-delegation | A 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 |
Authorization | The 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.
| Header | Value |
|---|---|
x-omnia-namespace | The agent’s namespace |
x-omnia-request-id | The per-request correlation ID |
x-omnia-user-id | The end user’s ID, pseudonymised |
x-omnia-subject-id | The pseudonymised ID of the token holder. Absent when the token holder is the end user |
x-omnia-user-email | The end user’s email address |
x-omnia-provider | The spec.type of the agent’s Provider, such as claude or openai |
x-omnia-model | The agent’s model. Absent when the Provider sets none |
x-omnia-origin | The auth validator that admitted the request |
x-omnia-workspace | The 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.
Response
Section titled “Response”| Backend response | Result for the model |
|---|---|
| 2xx, body is valid JSON | The 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 status | A 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.
gRPC handler
Section titled “gRPC handler”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);}Messages
Section titled “Messages”| Message | Field | Type | Number |
|---|---|---|---|
ToolRequest | tool_name | string | 1 |
arguments_json | string (JSON) | 2 | |
metadata | map<string, string> | 3 | |
ToolResponse | result_json | string (JSON) | 1 |
is_error | bool | 2 | |
error_message | string | 3 | |
ListToolsRequest | none | ||
ListToolsResponse | tools | repeated ToolInfo | 1 |
ToolInfo | name | string | 1 |
description | string | 2 | |
input_schema | string (JSON Schema) | 3 |
Execute
Section titled “Execute”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 response | Result for the model |
|---|---|
is_error false, result_json set | result_json |
is_error false, result_json empty | null |
is_error true | A 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.
ListTools
Section titled “ListTools”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.
Transport
Section titled “Transport”grpcConfig.tls defaults to false, which dials plaintext. tlsCertPath takes
effect only together with tlsKeyPath. See the
gRPC handler options.