# Grid-agent perception tools

The grid agent exposes compact read-only projections of state that the existing
native managers have already observed. A tool call never starts a directory
search, fetches an asset, selects an object, accepts inventory, sends a packet,
or mutates the world. The snapshot boundary is enabled only after the native
event queue reports readiness and is fenced by both session generation and
region UUID.

Every result has `schema_version`, `tool`, `generation`, `region_id`,
`observed_unix_millis`, `freshness`, `trust`, and `provenance`. `freshness` is
`observed` for a new snapshot and `cached` for a snapshot reused within the
two-second TTL. Missing manager facts are structured `{ "status": "unknown",
"reason": "manager_cache_unavailable" }` values. Deterministic distances and
cardinal directions are declared as derived fields; `model_inference` is always
`none`. Names, descriptions, hover text, parcel text, and inventory paths are
marked `untrusted_observed_data`, stripped of controls and URL-shaped tokens,
and limited to 256 UTF-8 bytes.

All eight tools are registered as policy capability `Informational`, risk
`ReadOnly`, idempotent, fixed cost one tool call, with no approval. The five
world-state tools may be offered to public chat and IM. Inventory search,
received landmarks, and recent participants are owner-private projections and
are exposed only to authorized IM, authenticated local operators, or explicitly
granted scheduler runs. The interaction intent filter further narrows which
informational tools a particular conversation may see.

| Tool | Arguments | Result projection | Example |
| --- | --- | --- | --- |
| `world_location` | `{}` | region name and agent position | `{"generation":4,"region_id":"…","position":{"x":128,"y":64,"z":24}}` |
| `agent_state` | `{}` | agent UUID, position, health, sitting local ID | `{"health":100,"sitting_on_local_id":{"status":"unknown","reason":"manager_cache_unavailable"}}` |
| `nearby_avatars` | optional `radius_meters`, `page`, `page_size` | UUID, name, position, distance, direction | `{"items":[{"name":"A Resident","distance_meters":3.2,"direction":"north"}]}` |
| `visible_objects` | optional `radius_meters`, `page`, `page_size` | non-attachment UUID/local ID, safe text, position and scale | `{"items":[{"name":"Cube","local_id":12,"trust":"untrusted_observed_data"}]}` |
| `parcel_environment` | `{}` | safe current parcel fields and cached terrain/environment facts | `{"parcel":{"status":"observed","area":512},"environment":{"water_height":20,"terrain_height":24}}` |
| `inventory_search` | required `query`; optional `page`, `page_size` | cached item UUID, name, type, path and modification time | `{"items":[{"name":"Example","kind":"LSL","path":"/Scripts/Example"}]}` |
| `received_landmarks` | optional `page`, `page_size` | cached landmark inventory metadata | `{"items":[{"name":"Home","region_id":{"status":"unknown","reason":"manager_cache_unavailable"}}]}` |
| `recent_participants` | optional `page`, `page_size` | avatar UUID, channel and last-active time only | `{"items":[{"avatar_id":"…","channel":"direct_im"}]}` |

Radius is limited to 256 metres, page size to 20, page number to 1,000,
inventory queries to 128 bytes, each source collection to 2,048 entries, and
each encoded result to 32 KiB. Ordering is distance then UUID for world items,
path/name then UUID for inventory and landmarks, and last-active time then UUID
and channel for participants. Paged results set `source_truncated` when a native
cache contained more than the inspected bound, so a bounded total is never
presented as complete. Attachments are excluded. Owner identities,
permissions, sale data, asset and capability URLs, media URLs, raw assets,
inventory bodies, and all conversation content are absent by construction.

Snapshot capture has a three-second deadline and observes cancellation. A
disconnect, reconnect, region crossing, or generation change invalidates the
cache. Observability receives only authorization/call/tool identifiers, outcome,
duration, result byte count, and cache-hit status; arguments and result payloads
are never logged.
