---
sidebar:
  hidden: true
title: roboto.domain.metrics.record
---
## Module Contents

### AggregateMetricRecord

```python
class roboto.domain.metrics.record.AggregateMetricRecord(/, **data: Any)
```

`from roboto.domain.metrics.record import AggregateMetricRecord`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L155-L172)

Bases: `pydantic.BaseModel`

**!!! abstract "Usage Documentation"**

\[Models\](../concepts/models.md)

A base class for creating Pydantic models.

**Parameters**

- **data** (`Any`)

**Attributes**

- **`AggregateMetricRecord.__class_vars__`**: The names of the class variables defined on the model.
- **`AggregateMetricRecord.__private_attributes__`**: Metadata about the private attributes of the model.
- **`AggregateMetricRecord.__signature__`**: The synthesized \_\_init\_\_ [Signature][inspect.Signature] of the model.
- **`AggregateMetricRecord.__pydantic_complete__`**: Whether model building is completed, or if there are still undefined fields.
- **`AggregateMetricRecord.__pydantic_core_schema__`**: The core schema of the model.
- **`AggregateMetricRecord.__pydantic_custom_init__`**: Whether the model has a custom \_\_init\_\_ function.
- **`AggregateMetricRecord.__pydantic_decorators__`**: Metadata containing the decorators defined on the model. This replaces Model.\_\_validators\_\_ and Model.\_\_root_validators\_\_ from Pydantic V1.
- **`AggregateMetricRecord.__pydantic_generic_metadata__`**: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [\_\_origin\_\_][genericalias.\_\_origin\_\_] and [\_\_args\_\_][genericalias.\_\_args\_\_] attributes of [generic aliases][types-genericalias], and the parameter item maps to the \_\_parameter\_\_ attribute of generic classes.
- **`AggregateMetricRecord.__pydantic_parent_namespace__`**: Parent namespace of the model, used for automatic rebuilding of models.
- **`AggregateMetricRecord.__pydantic_post_init__`**: The name of the post-init method for the model, if defined.
- **`AggregateMetricRecord.__pydantic_root_model__`**: Whether the model is a [RootModel][pydantic.root_model.RootModel].
- **`AggregateMetricRecord.__pydantic_serializer__`**: The pydantic-core SchemaSerializer used to dump instances of the model.
- **`AggregateMetricRecord.__pydantic_validator__`**: The pydantic-core SchemaValidator used to validate instances of the model.
- **`AggregateMetricRecord.__pydantic_fields__`**: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
- **`AggregateMetricRecord.__pydantic_computed_fields__`**: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
- **`AggregateMetricRecord.__pydantic_extra__`**: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
- **`AggregateMetricRecord.__pydantic_fields_set__`**: The names of fields explicitly set during instantiation.
- **`AggregateMetricRecord.__pydantic_private__`**: Values of private attributes set on the model instance.
- **AggregateMetricRecord.end_time** (`int`): Exclusive end of this period bucket, in Unix-epoch nanoseconds (UTC).
- **AggregateMetricRecord.metric_id** (`str`): Identifier of the aggregated metric definition.
- **AggregateMetricRecord.name** (`str`): Name of the aggregated metric.
- **AggregateMetricRecord.period** (`AggregationPeriod`): Calendar bucket size used for this aggregation.
- **AggregateMetricRecord.start_time** (`int`): Inclusive start of this period bucket, in Unix-epoch nanoseconds (UTC).
- **AggregateMetricRecord.total** (`int`): Number of raw observations that contributed to this bucket.

### AggregateMetricsRequest

```python
class roboto.domain.metrics.record.AggregateMetricsRequest(/, **data: Any)
```

`from roboto.domain.metrics import AggregateMetricsRequest`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L395-L455)

Bases: `pydantic.BaseModel`

Request payload for a numeric metric aggregation.

**Parameters**

- **data** (`Any`)

**Attributes**

- **AggregateMetricsRequest.aggregation** (`NumericAggregation`): Aggregation function to apply to the values in each bucket.

- **AggregateMetricsRequest.condition** (`roboto.query.ConditionType | None`) = `None`: Condition, or nested group of conditions, narrowing which data points are aggregated.

  Applied to individual data points rather than to bucket results, so it changes each bucket's value and total. A period whose data points are all filtered out yields no bucket at all, so a filtered aggregation can return fewer buckets than an unfiltered one over the same window. See [`condition`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.QueryMetricsRequest.condition) for the accepted fields and the treatment of data points published without a device.

- **AggregateMetricsRequest.end_time_ns** (`int`): Exclusive end of the aggregation window, in Unix-epoch nanoseconds (UTC). Built from [`aggregate()`](/reference/python-sdk/roboto/domain/metrics/metric#roboto.domain.metrics.metric.Metric.aggregate)'s `end_time` parameter the same way.

- **AggregateMetricsRequest.group_by** (`str | None`) = `None`: Field to split the aggregation by, in addition to the period bucket: one [`NumericAggregateMetricRecord`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.NumericAggregateMetricRecord) per (period, distinct value) pair, each carrying the value it aggregated under [`group_key`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.NumericAggregateMetricRecord.group_key).

  `None` aggregates every matching data point of a period into one bucket. Accepts `device.device_id` and String, Enum, or Boolean custom fields on sessions and devices (`session.custom.<name>`, `device.custom.<name>`); every other field of the vocabulary [`condition`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.AggregateMetricsRequest.condition) accepts is rejected, since a group key must be single-valued and low-cardinality to be a series. Data points carrying no value for the field are grouped under a null `group_key` rather than dropped, and the response is not capped: every distinct value with data in the window comes back.

- **AggregateMetricsRequest.include_device_ids** (`list[str] | roboto.sentinels.NotSetType | None`): Filter to observations from specific device IDs, `None` for null device_id only.

- **AggregateMetricsRequest.include_invocation_ids** (`list[str] | roboto.sentinels.NotSetType | None`): Filter to observations from specific invocation IDs, `None` for null invocation_id only.

- **AggregateMetricsRequest.include_session_ids** (`list[str] | roboto.sentinels.NotSetType`): Filter to observations for specific session IDs. `None` is not a valid value: `metrics.session_id` is non-nullable, so there is no "null session" subset to filter on. Omit (leave as [`NotSet`](/reference/python-sdk/roboto/sentinels#roboto.sentinels.NotSet)) for no filter, or pass a list of IDs.

- **AggregateMetricsRequest.model_config**: Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

- **AggregateMetricsRequest.name** (`str`): Name of the metric to aggregate.

- **AggregateMetricsRequest.period** (`AggregationPeriod`): Calendar bucket size to group observations by.

- **AggregateMetricsRequest.start_time_ns** (`int`): Inclusive start of the aggregation window, in Unix-epoch nanoseconds (UTC). Built by [`aggregate()`](/reference/python-sdk/roboto/domain/metrics/metric#roboto.domain.metrics.metric.Metric.aggregate) from its `start_time` parameter via [`to_epoch_nanoseconds()`](/reference/python-sdk/roboto/time#roboto.time.to_epoch_nanoseconds).

- **AggregateMetricsRequest.time_filter** (`MetricTimeFilter`): Whether to filter by session start time or end time.

### AggregationPeriod

```python
class roboto.domain.metrics.record.AggregationPeriod
```

`from roboto.domain.metrics import AggregationPeriod`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L19-L39)

Bases: `roboto.compat.StrEnum`

Calendar bucket size used when grouping metric observations.

All aggregation start/end times are based on UTC time.

**Attributes**

- **AggregationPeriod.Daily** = `'daily'`: One bucket per calendar day.
- **AggregationPeriod.Monthly** = `'monthly'`: One bucket per calendar month.
- **AggregationPeriod.Quarterly** = `'quarterly'`: One bucket per calendar quarter (three months).
- **AggregationPeriod.Weekly** = `'weekly'`: One bucket per calendar week.
- **AggregationPeriod.Yearly** = `'yearly'`: One bucket per calendar year.

### CreateMetricDefinitionRequest

```python
class roboto.domain.metrics.record.CreateMetricDefinitionRequest(/, **data: Any)
```

`from roboto.domain.metrics import CreateMetricDefinitionRequest`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L214-L225)

Bases: `pydantic.BaseModel`

Request payload to create a metric definition.

**Parameters**

- **data** (`Any`)

**Attributes**

- **CreateMetricDefinitionRequest.description** (`str | None`) = `None`: Human-readable description of what the metric measures.
- **CreateMetricDefinitionRequest.name** (`str`): Unique metric name.
- **CreateMetricDefinitionRequest.unit** (`MetricUnit | None`) = `None`: Unit of measure for values recorded under this metric, e.g. `"%"`, `"ms"`. Capped at 63 characters. `None` means unitless.

### MAX_METRIC_LIST_RESULTS

```python
roboto.domain.metrics.record.MAX_METRIC_LIST_RESULTS: int = 10000
```

`from roboto.domain.metrics import MAX_METRIC_LIST_RESULTS`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L280-L280)

Upper bound on the page size accepted by metric query and list calls.

[`query()`](/reference/python-sdk/roboto/domain/metrics/metric#roboto.domain.metrics.metric.Metric.query) auto-paginates with this value as the default page size, so total result-set size is unbounded. Callers can request smaller pages by setting [`max_results`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.QueryMetricsRequest.max_results).

[`get_by_session()`](/reference/python-sdk/roboto/domain/metrics/metric#roboto.domain.metrics.metric.Metric.get_by_session) does **not** paginate and is still capped at this many rows; sessions with more data points should use the paginated [`query()`](/reference/python-sdk/roboto/domain/metrics/metric#roboto.domain.metrics.metric.Metric.query) instead.

### MetricDefinitionRecord

```python
class roboto.domain.metrics.record.MetricDefinitionRecord(/, **data: Any)
```

`from roboto.domain.metrics import MetricDefinitionRecord`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L66-L95)

Bases: `pydantic.BaseModel`

A wire-transmissible representation of a metric definition.

**Parameters**

- **data** (`Any`)

**Attributes**

- **MetricDefinitionRecord.created** (`datetime.datetime`): Timestamp when this metric definition was created.
- **MetricDefinitionRecord.created_by** (`str`): User or service account that created this metric definition.
- **MetricDefinitionRecord.description** (`str | None`) = `None`: Human-readable description of what the metric measures.
- **MetricDefinitionRecord.metric_id** (`str`): Unique identifier for this metric definition.
- **MetricDefinitionRecord.modified** (`datetime.datetime`): Timestamp when this metric definition was last modified.
- **MetricDefinitionRecord.modified_by** (`str`): User or service account that last modified this metric definition.
- **MetricDefinitionRecord.name** (`str`): Unique name for this metric.
- **MetricDefinitionRecord.org_id** (`str`): Organization that owns this metric definition.
- **MetricDefinitionRecord.unit** (`str | None`) = `None`: Unit of measure for every value recorded under this metric, e.g. `"%"`, `"ms"`, `"m/s"`. Free-form and unvalidated; `None` means unitless.

### MetricEntry

```python
class roboto.domain.metrics.record.MetricEntry(/, **data: Any)
```

`from roboto.domain.metrics import MetricEntry`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L246-L254)

Bases: `pydantic.BaseModel`

A single name+value pair within a bulk metric publish.

**Parameters**

- **data** (`Any`)

**Attributes**

- **MetricEntry.name** (`str`): Name of the metric definition to record a value for. If the definition does not exist, it is auto-created.
- **MetricEntry.value** (`float`): Observed numeric value.

### MetricRecord

```python
class roboto.domain.metrics.record.MetricRecord(/, **data: Any)
```

`from roboto.domain.metrics import MetricRecord`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L98-L152)

Bases: `pydantic.BaseModel`

A wire-transmissible representation of a metric data point.

**Parameters**

- **data** (`Any`)

**Attributes**

- **MetricRecord.device_id** (`str | None`) = `None`: Device that produced the data.
- **MetricRecord.group_key** (`str | None`) = `None`: Value of the field named by [`QueryMetricsRequest.group_by`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.QueryMetricsRequest.group_by) that this data point carries, rendered as text whatever the field's type. `None` on every data point of an ungrouped query, and on a data point that carries no value for that field — one published without a device, or whose session or device has never been given a value for the custom field. Mirrors [`NumericAggregateMetricRecord.group_key`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.NumericAggregateMetricRecord.group_key), which splits buckets the same way.
- **MetricRecord.invocation_id** (`str | None`) = `None`: Action invocation that produced this data point, if any.
- **MetricRecord.max_timestamp_ns** (`int | None`) = `None`: Upper bound of the source session's aggregate timestamps, in Unix-epoch nanoseconds. `None` until the session has at least one file contribution. Mirrors [`max_timestamp_ns`](/reference/python-sdk/roboto/experimental/sessions/record#roboto.experimental.sessions.record.SessionRecord.max_timestamp_ns).
- **MetricRecord.metric_id** (`str`): Identifier of the metric definition this data point belongs to.
- **MetricRecord.min_timestamp_ns** (`int | None`) = `None`: Lower bound of the source session's aggregate timestamps, in Unix-epoch nanoseconds. `None` until the session has at least one file contribution. Mirrors [`min_timestamp_ns`](/reference/python-sdk/roboto/experimental/sessions/record#roboto.experimental.sessions.record.SessionRecord.min_timestamp_ns).
- **MetricRecord.name** (`str`): Human-readable name of the metric definition this data point belongs to. Resolved server-side from the parent [`MetricDefinitionRecord`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.MetricDefinitionRecord) so callers do not need a second lookup to display the metric name alongside the value.
- **MetricRecord.org_id** (`str`): Organization that owns this metric data point.
- **MetricRecord.published** (`datetime.datetime`): Timestamp when this data point was published to the platform.
- **MetricRecord.published_by** (`str`): User or service account that published this data point.
- **MetricRecord.session_id** (`str`): Session this metric is associated with.
- **MetricRecord.unit** (`str | None`) = `None`: Unit of measure for [`value`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.MetricRecord.value). Resolved server-side from the parent [`MetricDefinitionRecord`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.MetricDefinitionRecord), like [`name`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.MetricRecord.name), so callers can label a value without a second lookup. `None` means unitless.
- **MetricRecord.value** (`float`): Observed numeric value.

### MetricTimeFilter

```python
class roboto.domain.metrics.record.MetricTimeFilter
```

`from roboto.domain.metrics import MetricTimeFilter`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L61-L63)

Bases: `roboto.compat.StrEnum`

Enum where members are also (and must be) strings

**Attributes**

- **MetricTimeFilter.EndTime** = `'end_time'`
- **MetricTimeFilter.StartTime** = `'start_time'`

### MetricUnit

```python
roboto.domain.metrics.record.MetricUnit
```

`from roboto.domain.metrics.record import MetricUnit`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L211-L211)

### NumericAggregateMetricRecord

```python
class roboto.domain.metrics.record.NumericAggregateMetricRecord(/, **data: Any)
```

`from roboto.domain.metrics import NumericAggregateMetricRecord`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L175-L193)

Bases: [`AggregateMetricRecord`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.AggregateMetricRecord)

A wire-transmissible representation of one period bucket in a numeric metric aggregation.

**Parameters**

- **data** (`Any`)

**Attributes**

- **NumericAggregateMetricRecord.aggregation** (`NumericAggregation`): Aggregation function that was applied to produce this record.
- **NumericAggregateMetricRecord.group_key** (`str | None`) = `None`: Value of the field named by [`AggregateMetricsRequest.group_by`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.AggregateMetricsRequest.group_by) that this bucket's data points share, rendered as text whatever the field's type. `None` on every bucket of an ungrouped aggregation, and on the bucket collecting the grouped data points that carry no value for that field — a data point published without a device, or a session or device that has never been given a value for the custom field.
- **NumericAggregateMetricRecord.unit** (`str | None`) = `None`: Unit of measure for [`value`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.NumericAggregateMetricRecord.value), resolved from the aggregated metric's definition alongside [`name`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.AggregateMetricRecord.name). `None` means unitless.
- **NumericAggregateMetricRecord.value** (`float`): Aggregated result for this bucket.

### NumericAggregateMetricsResponse

```python
class roboto.domain.metrics.record.NumericAggregateMetricsResponse(/, **data: Any)
```

`from roboto.domain.metrics import NumericAggregateMetricsResponse`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L196-L203)

Bases: `pydantic.BaseModel`

Response payload for a numeric metric aggregation request.

**Parameters**

- **data** (`Any`)

**Attributes**

- **NumericAggregateMetricsResponse.aggregation** (`NumericAggregation`): Aggregation function that was applied.
- **NumericAggregateMetricsResponse.records** (`list[NumericAggregateMetricRecord]`): Period buckets returned by the aggregation, sorted by start_time ascending.

### NumericAggregation

```python
class roboto.domain.metrics.record.NumericAggregation
```

`from roboto.domain.metrics import NumericAggregation`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L42-L58)

Bases: `roboto.compat.StrEnum`

Aggregation function applied to numeric metric values within each period bucket.

**Attributes**

- **NumericAggregation.Count** = `'count'`: Count of observations in the bucket.
- **NumericAggregation.Max** = `'max'`: Maximum value observed in the bucket.
- **NumericAggregation.Mean** = `'mean'`: Arithmetic mean of all values in the bucket.
- **NumericAggregation.Min** = `'min'`: Minimum value observed in the bucket.
- **NumericAggregation.Sum** = `'sum'`: Sum of all values in the bucket.

### PublishMetricsRequest

```python
class roboto.domain.metrics.record.PublishMetricsRequest(/, **data: Any)
```

`from roboto.domain.metrics import PublishMetricsRequest`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L257-L273)

Bases: `pydantic.BaseModel`

Request payload to insert multiple metric data points in a single call.

**Parameters**

- **data** (`Any`)

**Attributes**

- **PublishMetricsRequest.device_id** (`roboto.sentinels.NotSetType | str | None`): Device that produced the data. When absent ([`NotSet`](/reference/python-sdk/roboto/sentinels#roboto.sentinels.NotSet)), the server infers the device from the session's attached devices: the request succeeds if exactly one device is attached and is rejected otherwise. Pass an explicit device ID or `None` to skip inference.
- **PublishMetricsRequest.metrics** (`list[MetricEntry]`): Metric data points to insert.
- **PublishMetricsRequest.model_config**: Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- **PublishMetricsRequest.session_id** (`str`): Session all metrics in this batch will be attached to.

### QueryMetricsRequest

```python
class roboto.domain.metrics.record.QueryMetricsRequest(/, **data: Any)
```

`from roboto.domain.metrics import QueryMetricsRequest`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L294-L392)

Bases: `pydantic.BaseModel`

Request payload to query raw metric data points.

**Parameters**

- **data** (`Any`)

**Attributes**

- **QueryMetricsRequest.condition** (`roboto.query.ConditionType | None`) = `None`: Condition, or nested group of conditions, narrowing which data points are returned.

  Every field must be prefixed with the entity it filters on, singular or plural; a bare field name such as `name` is rejected. The available fields are:

  - `session.<field>`: `session_id` (alias `id`), `name`, `min_timestamp_ns` (alias `start_time`), `max_timestamp_ns` (alias `end_time`), `duration`, `created`, `created_by`, `modified`, `modified_by`, `tags`. The two timestamp bounds accept anything [`to_epoch_nanoseconds()`](/reference/python-sdk/roboto/time#roboto.time.to_epoch_nanoseconds) converts; `duration` takes an integer count of nanoseconds.
  - `device.<field>`: `device_id` (alias `id`), `tags`, `created`, `created_by`, `modified`, `modified_by`, `metadata` (including dotted paths beneath it). Reads the device that published the data point, not the devices attached to its session.
  - `session.custom.<name>` / `device.custom.<name>` / `collection.custom.<name>`: a custom field in the `Ready` state.
  - `collection.collection_id` (alias `collection.id`): the data point's session belongs to that collection. `Equals` and `NotEquals` only.

  A session belongs to any number of collections, so a `collection.*` condition quantifies over that set: a data point matches when its session belongs to at least one collection satisfying the condition. A negated comparator (`NotEquals`, `NotContains`, `NotLike`) means the session belongs to no collection satisfying the positive form, so a session in no collection at all matches every negated collection condition. `IsNull` and `NotExists` likewise mean no collection the session belongs to carries a value for the field.

  A data point published without a device matches a `device.*` condition only under `IsNull` and `NotExists`. Every other comparator asks what the device's field holds, `NotEquals`, `NotContains`, and `NotLike` included, so a data point with no device, or a device carrying no value for the field, is excluded. Write `device.<field> NotEquals x OR device.<field> IsNull` to match both.

  Any other field, a comparator the field's type does not accept, a value the field cannot convert, or a [`Not`](/reference/python-sdk/roboto/query/conditions#roboto.query.conditions.ConditionOperator.Not) group raises [`RobotoIllegalArgumentException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoIllegalArgumentException).

- **QueryMetricsRequest.descending** (`bool`) = `False`: Order data points from the largest `sort_by` value to the smallest, instead of smallest first.

  With the default `sort_by`, this returns the most recent data points first.

- **QueryMetricsRequest.end_time_ns** (`int | None`) = `None`: Exclusive end of the query window, in Unix-epoch nanoseconds (UTC). Built from [`query()`](/reference/python-sdk/roboto/domain/metrics/metric#roboto.domain.metrics.metric.Metric.query)'s `end_time` parameter the same way. Defaults to `None` (now).

- **QueryMetricsRequest.group_by** (`str | None`) = `None`: Field whose value each returned data point should carry, under [`MetricRecord.group_key`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.MetricRecord.group_key).

  Unlike [`AggregateMetricsRequest.group_by`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.AggregateMetricsRequest.group_by), this does not change which rows come back or how many: a raw query already returns one data point per session, so there is nothing to split. It projects the field's value onto each one, which is what lets a caller separate the points into a series per distinct value without resolving the field itself.

  `None` leaves [`MetricRecord.group_key`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.MetricRecord.group_key) null on every data point. Accepts the same vocabulary the aggregation does — `device.device_id` and String, Enum, or Boolean custom fields on sessions and devices (`session.custom.<name>`, `device.custom.<name>`) — and rejects every other field of [`condition`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.QueryMetricsRequest.condition)'s vocabulary with [`RobotoIllegalArgumentException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoIllegalArgumentException). A data point carrying no value for the field gets a null `group_key` rather than being dropped.

- **QueryMetricsRequest.include_device_ids** (`list[str] | roboto.sentinels.NotSetType | None`): Filter to observations from specific device IDs, `None` for null device_id only.

- **QueryMetricsRequest.include_invocation_ids** (`list[str] | roboto.sentinels.NotSetType | None`): Filter to observations from specific invocation IDs, `None` for null invocation_id only.

- **QueryMetricsRequest.include_session_ids** (`list[str] | roboto.sentinels.NotSetType`): Filter to observations for specific session IDs. `None` is not a valid value: `metrics.session_id` is non-nullable, so there is no "null session" subset to filter on. Omit (leave as [`NotSet`](/reference/python-sdk/roboto/sentinels#roboto.sentinels.NotSet)) for no filter, or pass a list of IDs.

- **QueryMetricsRequest.max_results** (`int`) = `None`: Maximum number of data points to return. Must be between 1 and [`MAX_METRIC_LIST_RESULTS`](/reference/python-sdk/roboto/domain/metrics/record#roboto.domain.metrics.record.MAX_METRIC_LIST_RESULTS) (10,000).

- **QueryMetricsRequest.model_config**: Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

- **QueryMetricsRequest.name** (`str`): Name of the metric to query.

- **QueryMetricsRequest.sort_by** (`str | None`) = `None`: Field to order data points by, with `session_id` as a deterministic tiebreaker.

  One of `time` (the session time selected by `time_filter`), `value`, `published`, `device_id`, `session_id` or `invocation_id`; any other field is rejected with [`RobotoInvalidRequestException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoInvalidRequestException). Data points with no `device_id` or `invocation_id` sort after every other value. Defaults to `time`.

- **QueryMetricsRequest.start_time_ns** (`int | None`) = `None`: Inclusive start of the query window, in Unix-epoch nanoseconds (UTC). Built by [`query()`](/reference/python-sdk/roboto/domain/metrics/metric#roboto.domain.metrics.metric.Metric.query) from its `start_time` parameter via [`to_epoch_nanoseconds()`](/reference/python-sdk/roboto/time#roboto.time.to_epoch_nanoseconds). Defaults to `None` (the Unix epoch).

- **QueryMetricsRequest.time_filter** (`MetricTimeFilter`): Whether to filter by session start time or end time.

### UpdateMetricDefinitionRequest

```python
class roboto.domain.metrics.record.UpdateMetricDefinitionRequest(/, **data: Any)
```

`from roboto.domain.metrics import UpdateMetricDefinitionRequest`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/domain/metrics/record.py#L228-L238)

Bases: `pydantic.BaseModel`

Request payload to update a metric definition.

**Parameters**

- **data** (`Any`)

**Attributes**

- **UpdateMetricDefinitionRequest.description** (`roboto.sentinels.NotSetType | str | None`): New description, `None` to clear, or [`NotSet`](/reference/python-sdk/roboto/sentinels#roboto.sentinels.NotSet) to leave unchanged.
- **UpdateMetricDefinitionRequest.model_config**: Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- **UpdateMetricDefinitionRequest.unit** (`roboto.sentinels.NotSetType | MetricUnit | None`): New unit of measure (max 63 characters), `None` to clear, or [`NotSet`](/reference/python-sdk/roboto/sentinels#roboto.sentinels.NotSet) to leave unchanged.
