Sense Data
The Sense stage collects data from your external sources and passes the data to the Reason stage. In each cycle, all configured Sense substages run in order, and the platform merges their results for analysis.
You configure the Sense stage in stage 03 of the Agent Builder.
In the agent template YAML, you define the stage under stages.sense.substages.
Add one or more substages of different types to collect from multiple sources in a single cycle.
|
Every Sense substage writes into |
Substage Types
| Type | What it Does |
|---|---|
|
Subscribes to MQTT topics and collects messages. |
|
Makes HTTP requests to a REST API. |
|
Runs an SQL query against a configured database. |
|
Reads and parses a CSV file from a local path or URL. |
|
Collects messages from the agent bus discussion channel. |
|
Sandbox Mode: To run agents without live data sources during development or testing, set |
MQTT
Subscribe to MQTT topics and collect messages that arrive within the timeout window:
sense:
substages:
- type: mqtt
name: quality-metrics
connection: factory-mqtt # Name from your connections: block
config:
topics:
- factory/quality/metrics
- factory/quality/+/inspection # MQTT wildcards supported
- factory/sensors/#
timeoutMs: 15000 # Wait up to 15 seconds for messages
The mqtt substage collects messages into environmentalData.payload, with one entry per topic.
In the Reason stage, a large language model (LLM) prompt reads the payload object as {{environmentalData}}, so reference it with {{environmentalData | json}}.
For the exact property names, see Where the Platform Stores Sensed Data.
|
Set |
API
Make HTTP requests to a configured REST API:
sense:
substages:
- type: api
name: erp-data
connection: erp-api # Name from your connections: block
config:
endpoints:
- name: active-orders # ← becomes the payload key
path: /api/v1/production-orders/active
method: GET
params:
site: berlin
status: running
The api substage places the response body of each endpoint in environmentalData.payload, under the endpoint name. For example, environmentalData.payload["active-orders"].
Database
Run an SQL query against a configured database:
sense:
substages:
- type: database
name: recent-defects
connection: quality-db
config:
query:
name: recent-defects # ← becomes the payload key
sql: |
SELECT defect_type, count(*) as count, avg(severity) as avg_severity
FROM defects
WHERE created_at > NOW() - INTERVAL '1 hour'
GROUP BY defect_type
ORDER BY count DESC
LIMIT 20
The database substage places the query result in environmentalData.payload, under the query name, as an array of row objects. For example, environmentalData.payload["recent-defects"].
CSV
Read and parse a CSV file from a local path or URL:
sense:
substages:
- type: csv
name: shift-schedule # Becomes the property name in payload
config:
path: /data/shift-schedule.csv # Local path or URL
The csv substage places the parsed file in environmentalData.payload under the substage name, as an object with rows, columns, and totalRows. For example, environmentalData.payload["shift-schedule"].
Agent Messages
The agent-messages substage collects messages from the agent bus discussion channel.
Use this substage when an agent responds to instructions from other agents or from operators.
sense:
substages:
- type: agent-messages
name: instruction-collector
config:
maxMessages: 10
timeoutMs: 5000
The agent-messages substage places messages in environmentalData.payload.agentMessages.
Windowing and Aggregation
By default, each cycle sees only the raw observations of that cycle. A window buffers observations across multiple cycles and gives the Reason stage aggregated statistics (average, maximum, trend) instead of raw values.
Use a window to detect trends rather than react to individual spikes:
sense:
window:
size: 10 # Buffer the last 10 observations
slide: 1 # Advance by 1 each cycle (rolling window)
minSize: 5 # Wait until at least 5 observations before forwarding
aggregations:
- name: avg_temp
field: payload.temperature
function: avg
- name: max_temp
field: payload.temperature
function: max
- name: temp_slope
field: payload.temperature
function: slope # Positive = rising, negative = falling
- name: reading_count
function: count # Number of observations in the window
The Reason stage reads aggregated values as _aggregations.<substage-name>.<aggregation-name>:
{{_aggregations.quality-metrics.avg_temp}}
{{_aggregations.quality-metrics.temp_slope}}
Available Aggregation Functions
| Function | Result |
|---|---|
|
Mean value. |
|
Sum of all values. |
|
Smallest value. |
|
Largest value. |
|
Number of observations. |
|
First value in window. |
|
Most recent value. |
|
Standard deviation. |
|
Statistical variance. |
|
50th percentile. |
|
95th percentile. |
|
99th percentile. |
|
Linear trend direction. |
|
Max minus min. |
Payload Interpretation
When your incoming data has a variable or unpredictable structure, the interpret block uses the LLM to normalize the data into a consistent structure before Reason reads it.
Use interpretation when multiple device types publish different payload formats to your topics:
sense:
substages:
- type: mqtt
name: heterogeneous-sensors
connection: factory-mqtt
config:
topics:
- sensors/+/telemetry
timeoutMs: 10000
interpret:
instructions: |
Normalise the incoming sensor payload into a consistent structure.
Extract temperature (in °C), pressure (in hPa), and any alert flags.
output_schema:
type: object
properties:
temperature_c:
type: number
pressure_hpa:
type: number
alert:
type: boolean
The LLM normalizes each unique payload structure once, and the platform caches the result. The platform normalizes subsequent messages with the same structure without another LLM call.
The Reason stage receives the normalized interpreted data alongside the raw original payload.
Where the Platform Stores Sensed Data
Each cycle runs against a shared state object.
The Sense stage writes everything that it collects into environmentalData.payload, and the Reason and Reflect stages read from there.
The platform fully replaces environmentalData every cycle.
The platform discards the sensed data of the previous cycle unless you carry the data forward through memory or a window.
The location of each source in payload depends on the substage type and on whether you configure a window.
Storage Without a Window (Default)
| Source Type | Source Identifier | Memory Location |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
(fixed key) |
|
The platform keeps only the latest message per MQTT topic and discards older readings that arrive during the same Sense cycle. If you need all readings, configure a window.
When several substages run in the same cycle, the platform merges their outputs into a single flat payload object.
If two substages produce the same property name, the platform keeps the value from the later substage.
Keep your topic, query, and endpoint names distinct.
|
Slash-keyed topics require bracket notation. MQTT topic keys contain |
Storage With a Window
When you add a window block, the property names change.
Instead of one entry per topic, query, or endpoint, you get one entry per substage, and the entry holds the full window of observations.
Aggregations and window metadata appear in their own top-level fields.
| Field | Contents |
|---|---|
|
Array of the observations that the window collected (up to the configured |
|
One entry per aggregation you configured ( |
|
Window size and first and last timestamps. |
Because the property names change completely, use either windowed or non-windowed configuration per agent.
The same Reason prompt or condition cannot serve both.
A windowed substage also produces nothing until its buffer fills.
Design your rules and prompts to tolerate a no-data cycle.
Treat _aggregations[<substageName>] as possibly undefined.
Next Steps
-
Reason on Data: Analyze the collected data with rules or an LLM and plan actions.
-
Set Up Connections: Define the brokers, databases, and APIs that the Sense substages reference.