feat(grid-agent): add chat and IM interactions (#123)
Some checks failed
CI / rust-skia (Rust only) (push) Successful in 2m44s
CI / required (push) Failing after 2m41s

This commit is contained in:
2026-08-17 23:11:04 +00:00
parent e3ed39471b
commit 26fd2bf714
12 changed files with 3280 additions and 19 deletions

View File

@@ -28,6 +28,9 @@ observable receivers.
| 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 request slots | shared `LlmClient` semaphore | 256 hard / configured concurrent requests | async acquire or cancellation |
| Reasoning/tool session | `ToolLoop` caller | 32 turns / 256 calls hard, with lower configured limits | total timeout, cancellation, or supersession |
| Policy tools / approvals / schedules | `PolicyGateway` mutex | 64 tools / 4,096 approval records / 1,024 scheduler grants hard | deny before opaque authorization |
@@ -89,6 +92,11 @@ cleanup, fencing old events and late LLM/tool results. See
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.
@@ -123,3 +131,6 @@ 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).

View File

@@ -0,0 +1,61 @@
# Grid-agent chat and instant-message interaction
`InteractionCoordinator` is the single bounded owner for public chat and
one-to-one instant messages. A live session generation installs exactly one
native `AgentManager` chat subscription and one IM subscription. Their RAII
guards are removed before logout. Connect and disconnect state travels on a
separate watch channel, so inbound queue saturation cannot delay generation
cancellation or reconnect fencing.
## Admission and routing
Inputs are normalized into bounded values before enqueue. Self messages,
objects and system chat, muted residents, typing notifications, group or
conference IMs, malformed or oversized input, repeated delivery IDs, and
reflections of delivered output are suppressed. Public chat is admitted only
for a configured alias or mention, a brief nearby greeting, or a short-lived
follow-up from a resident already engaged by the agent. Ambient region chat is
not sent to the model.
Public chat always has `Public` origin, even when the resident UUID appears in
the operator allowlist. Public commands receive a fixed denial; public LSL
requests remain policy-gated. Direct-message authority is derived solely from
the sender UUID in `authorized_avatar_uuids`. Text claiming to be an operator
cannot change that origin. Unprivileged IM remains informational, while an
authorized IM may expose only the tools returned by `PolicyGateway` for its
immutable request context. Unknown or unregistered tools fail closed.
Each avatar and channel has an independent FIFO with fragment debounce. A
round-robin ready queue permits at most one active request per FIFO and enforces
the configured global inference cap, so a slow resident does not block other
residents or lifecycle work. Direct-message context expires after 24 hours as
defined by `ConversationStore`; public and direct context never mix.
## Delivery and safety
Model work has a configured deadline and shares generation cancellation.
Visible text is checked for credential, authorization, hidden-prompt, and tool
schema markers; URLs are omitted and ASCII mentions are neutralized. The total
response is bounded, then split only at UTF-8 boundaries into at most 1,023-byte
grid messages. Public chat and IM use independent rate limiters.
Every outbound part carries its trigger delivery ID, conversation session ID,
session generation, channel, part index, and part count. A delivery observation
records success, timeout, policy denial, or failure plus the number of parts
actually delivered. Fixed busy/failure text is emitted only for an admitted
interaction. Successful public replies also publish a content-free attention
request for later avatar behavior work.
## Shutdown and focused verification
Disconnect cancels all generation tasks and drops queued input. Reconnect
starts a fresh generation without clearing the bounded duplicate/reflection
history. Shutdown disconnects first, joins every model/delivery task within the
configured deadline, and flushes conversation persistence. No callback or task
is detached.
```sh
cargo test --locked -p metacrate-grid-agent --lib interaction_tests
cargo test --locked -p metacrate-grid-agent --test dependency_policy
cargo clippy --locked -p metacrate-grid-agent --all-targets -- -D warnings
```