95 lines
4.9 KiB
Markdown
95 lines
4.9 KiB
Markdown
# Grid-agent control plane v1
|
|
|
|
The grid agent exposes one transport-neutral request/response and event API.
|
|
Integrated clients receive an `InProcessControlClient`; split clients use the
|
|
same `ControlRequestEnvelope`, `ControlResponseEnvelope`, and `ControlEvent`
|
|
types over TCP. No terminal, Unix socket, named-pipe, permission-bit, or
|
|
platform-specific type appears in the core API.
|
|
|
|
## Transport and negotiation
|
|
|
|
TCP frames are a four-byte unsigned big-endian length followed by one UTF-8
|
|
JSON value. Empty, partial, malformed, idle, and oversized frames close the
|
|
connection within configured deadlines. The first frame must be:
|
|
|
|
```json
|
|
{"frame":"hello","body":{"version":1,"token":"separate-operator-capability"}}
|
|
```
|
|
|
|
The server answers with a `hello` containing version `1`, the authenticated
|
|
`operator` or `observer` role, or a typed error. Every later client frame is a
|
|
`request`; server frames are `response` or `event`. Request IDs contain at most
|
|
96 ASCII identifier bytes and cannot be replayed on a connection. A caller can
|
|
cancel an active request by its ID. Responses and events can arrive in either
|
|
order, so clients correlate responses by request ID.
|
|
|
|
Plain TCP binds only to IPv4 or IPv6 loopback. Remote control is off by default
|
|
and a non-loopback address is rejected unless both DER certificate and private
|
|
key paths are explicitly configured. Remote mode uses Rustls before the hello
|
|
exchange and emits an operator warning at startup. The TLS client API requires
|
|
the embedding client to supply its certificate roots and server-name policy.
|
|
Every split connection must still authenticate with a dedicated control token;
|
|
observer and operator tokens must differ and configuration rejects reuse of an
|
|
LLM API key or grid password. Tokens are absent from protocol errors, audit,
|
|
serialization traits, and diagnostics.
|
|
|
|
Remote service configuration uses the JSON fields
|
|
`control.remote_tls_certificate_der` and
|
|
`control.remote_tls_private_key_der` together with a non-loopback
|
|
`control.listen` value. Both files are bounded, non-symlink DER files. Omitting
|
|
either field, or selecting a non-loopback address without both, fails
|
|
configuration before a listener is created.
|
|
|
|
## Requests
|
|
|
|
The JSON request envelope is stable and versioned. For example:
|
|
|
|
```json
|
|
{"version":1,"request_id":"health-1","request":{"method":"health"}}
|
|
```
|
|
|
|
Observers can call `health`, `metrics`, `runtime`, `list_sessions`,
|
|
`list_scheduled_jobs`, `list_pending_approvals`, `list_audit_events`,
|
|
`list_observability_events`, and `subscribe_events`. Operators can additionally
|
|
call `cancel_request`, `pause_autonomy`, `resume_autonomy`, `cancel_action`,
|
|
`decide_approval`, `force_reconnect`, `expire_conversation`, `set_roaming_job`,
|
|
`inject_operator_message`, and `graceful_shutdown`. Cancellation is a mutation
|
|
and is operator-only. List requests use an opaque numeric cursor and a page
|
|
size of 1 through 100.
|
|
|
|
Runtime projections contain lifecycle/readiness, session generation, safe
|
|
region and pose fields when known, behavior mode, control-queue utilization,
|
|
and aggregate budget use. Conversation responses contain metadata only. Audit
|
|
and approval responses exclude arguments, prompt contents, credentials,
|
|
authorization headers, capability URLs, model reasoning, and filesystem data.
|
|
Unified events use pseudonymous correlation IDs and fixed-cardinality metrics;
|
|
their schema, journal, redaction, and replay rules are documented in
|
|
[`grid-agent-observability.md`](grid-agent-observability.md).
|
|
`cancel_action` binds to the exact bounded action ID carried by behavior audit
|
|
observations; it can cancel a queued or executing embodied action without
|
|
preempting unrelated work. The built-in roaming job ID is `default-roaming`.
|
|
|
|
Errors are typed as `authentication_failed`, `version_mismatch`,
|
|
`permission_denied`, `invalid_request`, `replay`, `not_found`, `conflict`,
|
|
`cancelled`, `timed_out`, `busy`, `backpressure`, `frame_too_large`,
|
|
`idle_timeout`, `transport_closed`, or `internal`, with a bounded safe message
|
|
and a retryable flag.
|
|
|
|
## Events, bounds, and reconnect
|
|
|
|
Events carry monotonically increasing sequence numbers. A subscription can
|
|
resume after its last observed sequence. If retained history no longer covers
|
|
that point, its first item is an explicit `gap` with `first_available` and
|
|
`last_missed`, followed by retained events. Mutation events record the
|
|
authenticated role/connection principal, operation name, and completed or
|
|
rejected outcome, never request contents.
|
|
|
|
Connections, unauthenticated handshakes, in-flight request tasks,
|
|
subscriptions, command/event queues, replay history, event history, event
|
|
bytes, event rate, frames, pages, idle time, request time, and writes all have
|
|
validated hard bounds. A full event or writer queue disconnects the slow
|
|
consumer instead of blocking the headless service. With zero clients, event
|
|
publication retains only the configured history and creates no background
|
|
work. Server shutdown cancels and joins all listener, connection, request, and
|
|
writer tasks within its deadline.
|