144 lines
9.3 KiB
Markdown
144 lines
9.3 KiB
Markdown
# Grid-agent architecture foundation
|
|
|
|
The grid agent is a workspace-owned Rust library and small service binary. Its
|
|
core depends on Tokio for scheduling and bounded channels. Its `live-grid`
|
|
feature owns the existing `libremetaverse` composition root for grid protocol
|
|
managers; the default offline graph does not compile live transports. It does
|
|
not create a second login, UDP, capabilities, inventory, or world client. It contains no
|
|
CLR/.NET loading, sidecar, subprocess adapter, provider SDK, native ABI, or
|
|
platform-specific core path.
|
|
|
|
## Ownership and bounds
|
|
|
|
`AgentService::start` owns offline task creation, while
|
|
`SessionSupervisor::start` owns the live lifecycle task. Configuration is
|
|
validated before either allocates channels, calls a backend, or permits network
|
|
access. Their handles exclusively own cancellation, join handles, controls, and
|
|
observable receivers.
|
|
|
|
| Resource | Owner | Hard/configured bound | Backpressure/termination |
|
|
| --- | --- | --- | --- |
|
|
| Grid-event queue | coordinator receives; backend sends | 8,192 / `grid_event_queue` | async send or cancellation |
|
|
| Control queue | coordinator receives; handle sends | 256 / `control_queue` | async send; closed after stop |
|
|
| Observable queue | handle receives; coordinator/backend send | 8,192 / `observable_queue` | async send or cancellation |
|
|
| Backend task | `ServiceHandle.tasks[0]` | exactly one in offline mode | shared cancellation token, joined first |
|
|
| Coordinator task | `ServiceHandle.tasks[1]` | exactly one | shared cancellation token, joined second |
|
|
| Live session supervisor | `SessionSupervisorHandle` | one owner; one active generation/session | generation cancellation, exact-once logout, bounded join |
|
|
| Offline session work | live supervisor | 1,024 hard / `reconnect.offline_work_capacity` | read-only queue; mutations rejected while not ready |
|
|
| Body / message | typed boundary owners | 8 MiB / 64 KiB hard ceilings, with lower configured limits | rejected before enqueue |
|
|
| Conversation / tool calls | request owner | 256 messages / 64 calls, with lower configured limits | rejected before request |
|
|
| Per-avatar conversation memory | `ConversationStore` mutex | 4,096 sessions / 64 MiB hard, lower `conversation` limits | monotonic expiry, deterministic compaction/LRU eviction |
|
|
| Interaction ingress / observations | `InteractionHandle` | 8,192 each hard, lower queue configuration | bounded admission; lifecycle uses nonblocking watch state |
|
|
| Per-avatar interaction FIFO | `InteractionCoordinator` | 4,096 senders / 64 messages each hard, lower `interaction` limits | fair ready queue, one active request per avatar/channel |
|
|
| Interaction inference / outbound | generation tasks and channel rate limiters | 64 concurrent hard; 1,023 bytes per grid part | timeout/cancellation fencing; independent public/IM pacing |
|
|
| LLM conversation runtime | avatar-scoped Mentra agent | configured model/tool budgets and 2-minute default wall time | SSE cancellation, compaction, or supersession |
|
|
| Autonomous approval review | fresh volatile Mentra runtime | one model request, no tools/history/memory | exact ALLOW/DENY; every error fails closed |
|
|
| Policy tools / approvals / schedules | `PolicyGateway` mutex | 64 tools / 4,096 approval records / 1,024 scheduler grants hard | deny before opaque authorization |
|
|
| Principal/global resource budget | `PolicyGateway` time window | validated calls, zero L$, upload, inventory, movement, and build ceilings | atomic charge or stable denial |
|
|
| Authorized avatars | immutable `AgentConfig` set | 1,024 hard ceiling, lower configured limit | malformed, nil, duplicate, and wildcard input rejected |
|
|
| Configuration / secret file | loader | 64 KiB / 16 KiB | regular non-symlink file only |
|
|
|
|
`BoundedText` and `BoundedVec` make message and collection ceilings part of the
|
|
type. Dynamic configuration can lower these absolute ceilings but cannot raise
|
|
them. Backend error text is not forwarded; observations publish a fixed bounded
|
|
diagnostic.
|
|
|
|
## State machines and shutdown
|
|
|
|
The explicit service states are `starting -> running <-> paused -> stopping ->
|
|
stopped`, with `failed` reserved for task failure. The offline backend publishes
|
|
`BackendReady`, after which the coordinator enters `running`. A shutdown control,
|
|
direct handle shutdown, backend failure, closed owner queue, or handle drop
|
|
triggers the same cancellation token.
|
|
|
|
Orderly shutdown first cancels, joins the backend, and then joins the
|
|
coordinator. Each join has the validated shutdown timeout. A late task is
|
|
aborted and awaited before return. A partially polled shutdown future only
|
|
borrows each join handle, so cancelling that future leaves every task in the
|
|
handle's fixed ownership slots for a retry or final drop. Dropping the handle
|
|
cancels and aborts all remaining owned tasks, so no task is detached. A
|
|
feature-enabled live adapter drops its
|
|
`LibremetaverseClientOwner` last, invoking the existing client ownership
|
|
shutdown.
|
|
|
|
Live modes use `stopped`, `connecting`, `degraded` (transport connected but not
|
|
fully ready), `online`, `backoff`, `authentication-blocked`, `paused`, and
|
|
`shutting-down`. Every attempt rotates a generation cancellation token.
|
|
Disconnect, pause, logout, force reconnect, or shutdown invalidates it before
|
|
cleanup, fencing old events and late LLM/tool results. See
|
|
[`grid-agent-session.md`](grid-agent-session.md).
|
|
|
|
## Trust boundaries
|
|
|
|
- YAML configuration and legacy migration input are untrusted. Unknown fields,
|
|
oversized files, invalid booleans, conflicting modes, non-HTTP(S) URLs,
|
|
URL fragments, malformed/noncanonical/nil UUIDs, wildcard authorization,
|
|
multiline secrets, and unsafe limits fail before startup.
|
|
- `SecretString` and `EndpointUrl` are the only credential-bearing value types.
|
|
Secrets are never serializable or printable. Endpoint diagnostics replace
|
|
user information, passwords, and the complete query.
|
|
- Grid input crosses `GridBackend` only through bounded `GridEvent` values.
|
|
The `live-grid` feature supplies `LibremetaverseClientOwner`; live
|
|
implementations must own it and reuse its client and managers.
|
|
- World changes cross only `WorldMutator::apply`, which always receives the
|
|
non-forgeable `AuthorizedAction` produced by `PolicyGateway`. Raw calls and
|
|
caller-created decisions are not accepted. This issue supplies no live
|
|
mutation implementation.
|
|
- LLM traffic crosses the configured provider base through Mentra's Responses
|
|
SSE runtime. MetaCrate supplies only endpoint, credential, model, permitted
|
|
tools, and run bounds. Proposed calls cross `PolicyToolExecutor` only after
|
|
Mentra schema handling and MetaCrate's independent policy evaluation.
|
|
- Conversation context is keyed by immutable avatar UUID and either public chat
|
|
or direct IM. Group channels are not representable. The LLM projection can
|
|
retrieve only one exact key, and recovered/untrusted summaries remain user-role
|
|
prompt data rather than system authority.
|
|
- Public-chat and direct-IM input crosses a bounded normalization boundary.
|
|
Authority is derived only from channel plus sender UUID; public chat can never
|
|
acquire operator authority. Output is safety-filtered, UTF-8 split, rate
|
|
limited, and associated with its trigger, session, generation, and delivery
|
|
result.
|
|
- Signals and console output belong to the binary. The reusable core relies on
|
|
no terminal, Unix socket, Unix signal, separator, or fixed platform path.
|
|
|
|
## Dependency diagram
|
|
|
|
```text
|
|
metacrate-grid-agent binary (portable Ctrl-C + config path)
|
|
|
|
|
v
|
|
offline AgentService -> bounded Tokio channels/tasks -> injected GridBackend
|
|
| |
|
|
v v
|
|
typed config/events/policy boundaries live-grid feature boundary
|
|
| |
|
|
+-----------------> libremetaverse-types +--> libremetaverse::GridClient
|
|
|
|
avatar session -> persistent Mentra agent -> Responses SSE / compaction / memory
|
|
|
|
|
+-> PolicyToolExecutor -> PolicyGateway
|
|
| |
|
|
| +-> AuthorizedToolBackend
|
|
+-> one-shot Mentra safety reviewer when required
|
|
|
|
scene snapshot -> cached headless wgpu color/depth render -> JPEG -> Mentra image
|
|
`-> deterministic software fallback
|
|
```
|
|
|
|
The package has no build script. Its cross-platform `wgpu` path uses the
|
|
platform graphics backend selected by wgpu and requires no window or display;
|
|
the software fallback remains available when adapter creation or rendering
|
|
fails. The focused
|
|
`dependency_policy` test rejects subprocess launch sites, unsafe/native ABI
|
|
source, build scripts, and unreviewed direct dependency names in this package.
|
|
The precise LLM compatibility and cancellation contract is documented in
|
|
[`grid-agent-llm.md`](grid-agent-llm.md).
|
|
The origin/capability matrix and opaque mutation boundary are documented in
|
|
[`grid-agent-policy.md`](grid-agent-policy.md).
|
|
The live lifecycle and generation contract is documented in
|
|
[`grid-agent-session.md`](grid-agent-session.md).
|
|
The conversation isolation and persistence contract is documented in
|
|
[`grid-agent-conversation.md`](grid-agent-conversation.md).
|
|
The public-chat/IM admission, fairness, authorization, egress, and lifecycle
|
|
contract is documented in
|
|
[`grid-agent-interaction.md`](grid-agent-interaction.md).
|