---
sidebar:
  hidden: true
title: roboto.ai.agent.record
---
## Module Contents

### AgentRecord

```python
class roboto.ai.agent.record.AgentRecord(/, **data: Any)
```

`from roboto.ai.agent import AgentRecord`

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

Bases: `pydantic.BaseModel`

A pre-filled [`StartAgentThreadRequest`](/reference/python-sdk/roboto/ai/agent_thread/record#roboto.ai.agent_thread.record.StartAgentThreadRequest) plus declared variables.

An [`AgentRecord`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.AgentRecord) captures *most* of what an [`AgentThread`](/reference/python-sdk/roboto/ai/agent_thread/agent_thread#roboto.ai.agent_thread.agent_thread.AgentThread) needs to start - system prompt, model profile, seeded messages, declared goals - and leaves a small set of named holes that callers must fill at invoke time. The canonical example is a triage agent whose goal carries a fixed `label_vocabulary` but a `{{dataset.id}}` placeholder, so the same agent can be re-run against many datasets without re-declaring the vocabulary.

The record's main invariant - enforced by `_validate_variables_match_placeholders()` \- is that the set of `{{...}}` placeholders found anywhere in [`request_template`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.AgentRecord.request_template) equals exactly `{v.name for v in variables}`. A mismatch fails at save time so stale invoke forms can't paper over typos.

**Parameters**

- **data** (`Any`)

**Attributes**

- **AgentRecord.agent_id** (`str`): Canonical handle. Generated server-side (`agt_<short>`); stable across renames.
- **AgentRecord.created** (`datetime.datetime`): Wall-clock time the record was first persisted.
- **AgentRecord.created_by** (`str`): User id of the agent's original author.
- **AgentRecord.description** (`str | None`) = `None`: Free-form description rendered on the agents list and detail pages.
- **AgentRecord.modified** (`datetime.datetime`): Wall-clock time of the most recent successful update.
- **AgentRecord.modified_by** (`str`): User id who applied the most recent update; equals [`created_by`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.AgentRecord.created_by) on records that have not been edited since creation.
- **AgentRecord.name** (`str`): Human-readable display name. Mutable. Unique per `(org_id, name)` \- enforced at the persistence layer, not on the record.
- **AgentRecord.org_id** (`str`): Organization that owns the agent. All CRUD and invoke calls must come from a member of this org.
- **AgentRecord.request_template** (`roboto.ai.agent_thread.record.StartAgentThreadRequest`): The body that will be cloned and resolved into a real [`StartAgentThreadRequest`](/reference/python-sdk/roboto/ai/agent_thread/record#roboto.ai.agent_thread.record.StartAgentThreadRequest) at invoke time. Any string leaf may contain `{{name}}` placeholders; non-string fields cannot be templated, because substitution visits string leaves only.
- **AgentRecord.variables** (`list[TemplateVariable]`) = `None`: Declared variables. The set of names here must equal the set of placeholder names parsed from [`request_template`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.AgentRecord.request_template).

### CreateAgentRequest

```python
class roboto.ai.agent.record.CreateAgentRequest(/, **data: Any)
```

`from roboto.ai.agent import CreateAgentRequest`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/agent/record.py#L218-L229)

Bases: `pydantic.BaseModel`

Wire payload for `POST /v1/ai/agents`.

The server fills [`AgentRecord.agent_id`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.AgentRecord.agent_id), `org_id`, `created_by`, `created`, `modified`, and `modified_by` from the caller's identity; everything else comes from this request.

**Parameters**

- **data** (`Any`)

**Attributes**

- **CreateAgentRequest.description** (`str | None`) = `None`
- **CreateAgentRequest.name** (`str`)
- **CreateAgentRequest.request_template** (`roboto.ai.agent_thread.record.StartAgentThreadRequest`)
- **CreateAgentRequest.variables** (`list[TemplateVariable]`) = `None`

### LaunchAgentRequest

```python
class roboto.ai.agent.record.LaunchAgentRequest(/, **data: Any)
```

`from roboto.ai.agent import LaunchAgentRequest`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/agent/record.py#L251-L278)

Bases: `pydantic.BaseModel`

Wire payload for `POST /v1/ai/agents/<agent_id>/launch`.

The route resolves the named agent, substitutes `values` into its body, and starts a new [`AgentThread`](/reference/python-sdk/roboto/ai/agent_thread/agent_thread#roboto.ai.agent_thread.agent_thread.AgentThread) whose visibility comes from [`visibility`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.LaunchAgentRequest.visibility) and whose `created_from_agent_id` points back at the source agent.

**Parameters**

- **data** (`Any`)

**Attributes**

- **LaunchAgentRequest.analysis_scope** (`roboto.ai.core.AnalysisScope | None`) = `None`: Optional [`AnalysisScope`](/reference/python-sdk/roboto/ai/core/context#roboto.ai.core.context.AnalysisScope) for the resulting thread. When provided, it is zipper-merged onto whatever the agent's `request_template.analysis_scope` field carries: each dimension the caller set wins, and the rest inherit from the template. When `None`, the authored template's scope (usually none) is left untouched.
- **LaunchAgentRequest.values** (`dict[str, str]`) = `None`: Variable name to caller-supplied value. Keys must match declared [`TemplateVariable`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.TemplateVariable) names; values are coerced to `str` before being spliced into placeholders.
- **LaunchAgentRequest.visibility** (`roboto.ai.agent_thread.record.ThreadVisibility`): Visibility of the resulting [`AgentThread`](/reference/python-sdk/roboto/ai/agent_thread/agent_thread#roboto.ai.agent_thread.agent_thread.AgentThread). Invoke-time wins: this value overrides whatever the agent's `request_template.visibility` field carries. Agents cannot pin visibility — authors who need to convey recommended visibility do so in the agent's `description`. Defaults to `ORG` because agents exist to share workflows across teammates; `PRIVATE` is an explicit opt-out per invocation.

### TemplateVariable

```python
class roboto.ai.agent.record.TemplateVariable(/, **data: Any)
```

`from roboto.ai.agent import TemplateVariable`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/agent/record.py#L47-L115)

Bases: `pydantic.BaseModel`

A named slot in an [`AgentRecord`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.AgentRecord) that must be filled before the agent can be invoked.

Variables are declared up-front rather than inferred from the body so that the invoke UI can render typed inputs (dataset pickers, etc.) and so that a typo in the body (`{{dataste.id}}`) surfaces as a save-time validation error rather than a silent extra prompt at invoke time. The declared set and the set of placeholders parsed from the body must match exactly - see `AgentRecord._validate_variables_match_placeholders()`.

**Parameters**

- **data** (`Any`)

**Attributes**

- **TemplateVariable.collection_content_type** (`roboto.domain.collections.record.CollectionResourceType | None`) = `None`: Only meaningful when [`type`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.TemplateVariable.type) is [`TemplateVariableType.COLLECTION_ID`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.TemplateVariableType.COLLECTION_ID): constrains the invoke-page collection picker to collections holding this resource type (e.g. `event` collections for a create-events goal). `None` leaves the picker unconstrained. Must be `None` for every other variable type — see `_validate_resolvable()`.
- **TemplateVariable.default** (`str | None`) = `None`: Default value substituted when the caller omits the variable. Coerced to `str`; types are a UI concern.
- **TemplateVariable.description** (`str | None`) = `None`: Human-readable explanation rendered next to the input on the invoke page.
- **TemplateVariable.name** (`str`): Lookup key for substitution. Must match [`VARIABLE_NAME_RE`](/reference/python-sdk/roboto/templating/substitution#roboto.templating.substitution.VARIABLE_NAME_RE); see that pattern for the dotted-name namespace convention. Two variables sharing a prefix (`dataset.id` \+ `dataset.name`) without an upstream expander produce two unlinked inputs at invoke time — that's a UI-authoring footgun, not an SDK contract.
- **TemplateVariable.required** (`bool`) = `True`: If `True` the resolver raises [`UnresolvedAgentVariablesError`](/reference/python-sdk/roboto/ai/agent/resolver#roboto.ai.agent.resolver.UnresolvedAgentVariablesError) when no value is supplied and no [`default`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.TemplateVariable.default) is set.
- **TemplateVariable.type** (`TemplateVariableType`): UI hint for the invoke page. See [`TemplateVariableType`](/reference/python-sdk/roboto/ai/agent/record#roboto.ai.agent.record.TemplateVariableType).

### TemplateVariableType

```python
class roboto.ai.agent.record.TemplateVariableType
```

`from roboto.ai.agent import TemplateVariableType`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/agent/record.py#L20-L44)

Bases: `roboto.compat.StrEnum`

How a variable's value is interpreted when an agent is launched.

Substitution itself is type-agnostic: every value is spliced in as a string. The type drives two things a caller can observe — the Roboto web app picks a richer input control (dataset picker, device picker), and a typed value is checked for existence when the agent is launched, so a bad id is rejected up front rather than inside the agent's first tool call.

**Attributes**

- **TemplateVariableType.COLLECTION_ID** = `'collection_id'`: A Roboto collection identifier. UI renders a collection picker; invoke-time validator asserts the collection exists in the caller's org.
- **TemplateVariableType.DATASET_ID** = `'dataset_id'`: A Roboto dataset identifier. UI renders a dataset picker; invoke-time validator asserts the dataset exists in the caller's org.
- **TemplateVariableType.DEVICE_ID** = `'device_id'`: A Roboto device identifier. UI renders a device picker; invoke-time validator asserts the device is registered in the caller's org.
- **TemplateVariableType.STRING** = `'string'`: Free-form text. The default; renders as a plain text input. No existence check (no entity to check against).

### UpdateAgentRequest

```python
class roboto.ai.agent.record.UpdateAgentRequest(/, **data: Any)
```

`from roboto.ai.agent import UpdateAgentRequest`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/agent/record.py#L232-L248)

Bases: `pydantic.BaseModel`

Wire payload for `PUT /v1/ai/agents/<agent_id>`.

Uses the [`NotSetType`](/reference/python-sdk/roboto/sentinels#roboto.sentinels.NotSetType) sentinel to distinguish "field omitted" from "field explicitly set to `None`" so partial updates don't accidentally null out unrelated fields.

**Parameters**

- **data** (`Any`)

**Attributes**

- **UpdateAgentRequest.description** (`str | None | roboto.sentinels.NotSetType`)
- **UpdateAgentRequest.model_config**: Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- **UpdateAgentRequest.name** (`str | roboto.sentinels.NotSetType`)
- **UpdateAgentRequest.request_template** (`roboto.ai.agent_thread.record.StartAgentThreadRequest | roboto.sentinels.NotSetType`)
- **UpdateAgentRequest.variables** (`list[TemplateVariable] | roboto.sentinels.NotSetType`)

### extract_placeholders()

```python
def roboto.ai.agent.record.extract_placeholders(
    body: roboto.ai.agent_thread.record.StartAgentThreadRequest,
) -> set[str]
```

`from roboto.ai.agent import extract_placeholders`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/agent/record.py#L206-L215)

Return every `{{name}}` placeholder referenced anywhere in `body`.

Walks the JSON form of the request rather than the Pydantic model so the traversal is type-agnostic - placeholders inside `label_vocabulary` values, message text, system prompt, etc. all get picked up without needing per-field logic. Only string *values* are scanned; dict keys are intentionally ignored so key-collision footguns never arise.

**Parameters**

- **body** (`roboto.ai.agent_thread.record.StartAgentThreadRequest`)

**Returns**

- `set[str]`
