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

- [AGENT_CONTENT_MODEL_BY_TYPE](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AGENT_CONTENT_MODEL_BY_TYPE) (data): `AGENT_CONTENT_MODEL_BY_TYPE: dict[AgentContentType, type[AgentContent]]`. The model class for each JSON-serialized content type, keyed by discriminator.

- [AgentClientContextEntry](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentClientContextEntry) (class): The caller's attached viewing context, carried on their own message.

- [AgentCompressionFillerContent](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentCompressionFillerContent) (class): Filler standing in for a message the compression deletion pass emptied.

- [AgentContent](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentContent) (type alias): `type AgentContent = AgentTextContent | AgentToolUseContent | AgentToolResultContent | AgentErrorContent | AgentDeletedContent | AgentCompressionFillerContent | AgentClientContextEntry`. Type alias for all possible content types within agent messages.

- [AgentContentType](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentContentType) (class): Enumeration of different types of content within agent messages.

- [AgentDeletedContent](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentDeletedContent) (class): Tombstone for a content block removed by compression.

- [AgentErrorContent](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentErrorContent) (class): Error content within an agent message.

- [AgentGoalStatus](/reference/python-sdk/roboto/ai/goals/types#roboto.ai.goals.types.AgentGoalStatus) (class): Lifecycle of a per-turn declared goal.

- [AgentSubtask](/reference/python-sdk/roboto/ai/core/task#roboto.ai.core.task.AgentSubtask) (class): A lightweight checklist item under a top-level task.

- [AgentSubtaskStatus](/reference/python-sdk/roboto/ai/core/task#roboto.ai.core.task.AgentSubtaskStatus) (class): Lifecycle state of a sub-task.

- [AgentTask](/reference/python-sdk/roboto/ai/core/task#roboto.ai.core.task.AgentTask) (class): A top-level task the agent is tracking within a thread.

- [AgentTaskBoundary](/reference/python-sdk/roboto/ai/core/task#roboto.ai.core.task.AgentTaskBoundary) (class): Position in the conversation where a top-level task's active span begins or ends.

- [AgentTaskMinimal](/reference/python-sdk/roboto/ai/core/task#roboto.ai.core.task.AgentTaskMinimal) (class): Minimal acknowledgement returned by the task mutation tools.

- [AgentTaskStatus](/reference/python-sdk/roboto/ai/core/task#roboto.ai.core.task.AgentTaskStatus) (class): Lifecycle state of a top-level agent task.

- [AgentTextContent](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentTextContent) (class): Text content within an agent message.

- [AgentToolResultContent](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentToolResultContent) (class): Tool execution result content within an agent message.

- [AgentToolUseContent](/reference/python-sdk/roboto/ai/core/content#roboto.ai.core.content.AgentToolUseContent) (class): Tool usage request content within an agent message.

### AgentMessage

```python
class roboto.ai.core.record.AgentMessage(/, **data: Any)
```

`from roboto.ai.agent_thread import AgentMessage`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L230-L286)

Bases: `pydantic.BaseModel`

A single message within an agent thread.

Represents one message in the conversation, containing the sender role, content blocks, and generation status. Messages can contain multiple content blocks of different types (text, tool use, tool results).

**Parameters**

- **data** (`Any`)

**Attributes**

- **AgentMessage.content** (`list[roboto.ai.core.content.AgentContent]`): List of content blocks that make up this message.
- **AgentMessage.created** (`datetime.datetime`) = `None`: Timestamp when this message was created.
- **AgentMessage.role** (`AgentRole`): The role of the message sender (user, assistant, or roboto).
- **AgentMessage.status** (`AgentMessageStatus`): Current generation status of this message.

#### AgentMessage.is_complete()

```python
def is_complete() -> bool
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L269-L275)

Check if message generation is complete.

**Returns**

- `bool`: True if the message status is COMPLETED, False otherwise.

#### AgentMessage.is_unsuccessful()

```python
def is_unsuccessful() -> bool
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L277-L286)

Check if message generation failed or was cancelled.

**Returns**

- `bool`: True if the message status is FAILED or CANCELLED, False otherwise.

#### AgentMessage.text()

```python
@classmethod
def text(text: str, role: AgentRole = AgentRole.USER) -> AgentMessage
```

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

Create a simple text message.

Convenience method for creating a message containing only text content.

**Parameters**

- **text** (`str`): The text content for the message.
- **role** (`AgentRole`): The role of the message sender. Defaults to USER.

**Returns**

- `AgentMessage`: AgentMessage instance containing the text content.

### AgentMessageStatus

```python
class roboto.ai.core.record.AgentMessageStatus
```

`from roboto.ai.agent_thread import AgentMessageStatus`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L142-L173)

Bases: `roboto.compat.StrEnum`

Enumeration of possible message generation states.

Tracks the lifecycle of message generation from initiation to completion.

**Attributes**

- **AgentMessageStatus.CANCELLED** = `'cancelled'`: Message generation was cancelled by the user.
- **AgentMessageStatus.COMPLETED** = `'completed'`: Message generation has finished and content is complete.
- **AgentMessageStatus.FAILED** = `'failed'`: Message generation failed due to an error.
- **AgentMessageStatus.GENERATING** = `'generating'`: Message content is currently being generated.
- **AgentMessageStatus.NOT_STARTED** = `'not_started'`: Message has been queued but generation has not begun.

#### AgentMessageStatus.is_terminal()

```python
def is_terminal() -> bool
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L163-L173)

Check if the message generation is in a terminal state.

**Returns**

- `bool`: True if the message is in a terminal state, False otherwise.

### AgentRole

```python
class roboto.ai.core.record.AgentRole
```

`from roboto.ai.agent_thread import AgentRole`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L126-L139)

Bases: `roboto.compat.StrEnum`

Enumeration of possible roles in an agent thread.

Defines the different participants that can send messages in a thread.

**Attributes**

- **AgentRole.ASSISTANT** = `'assistant'`: AI agent responding to user queries and requests.
- **AgentRole.ROBOTO** = `'roboto'`: Roboto system providing tool results and system information.
- **AgentRole.USER** = `'user'`: Human user sending messages to the agent.

### AgentThreadDelta

```python
class roboto.ai.core.record.AgentThreadDelta(/, **data: Any)
```

`from roboto.ai.agent_thread import AgentThreadDelta`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L460-L506)

Bases: `pydantic.BaseModel`

Incremental update to an agent thread.

Contains only the changes since the last synchronization, used for efficient real-time updates without transferring the entire thread history.

**Parameters**

- **data** (`Any`)

**Attributes**

- **AgentThreadDelta.continuation_token** (`str`): Updated token for the next incremental synchronization.

- **AgentThreadDelta.goals** (`list[AgentThreadGoalRecord] | None`) = `None`: Latest snapshot of every goal declared in the thread, ordered by allocation. `None` means there has been no change since the previous delta — clients should retain the snapshot they already hold. An empty list means the thread has no declared goals. A non-empty list is the authoritative current snapshot and replaces any prior value.

- **AgentThreadDelta.messages_by_idx** (`dict[int, AgentMessage]`): New or updated messages indexed by their position in the conversation.

- **AgentThreadDelta.reset_from_message_sequence_num** (`int | None`) = `None`: Discard held messages from this index onward before applying this delta.

  A delta's messages normally *extend* what a client already holds, because the server sends only content the client has not seen. That breaks when a turn is abandoned partway and regenerated: the replacement message reuses the same index, so what the client holds at that index is text from an attempt that no longer exists, and appending to it would splice the real reply onto a discarded draft.

  When this field is set, the client must truncate its held messages to indices strictly below it, then apply `messages_by_idx` and adopt `continuation_token` as usual — the server has rewound the stream to that point and will resend it. `None` (the common case) means append as normal.

- **AgentThreadDelta.status** (`AgentThreadStatus | None`) = `None`: Updated status of the agent thread.

- **AgentThreadDelta.tasks** (`list[roboto.ai.core.task.AgentTask] | None`) = `None`: Latest snapshot of the thread's task list, ordered by position. `None` means no change since the previous delta — clients should retain the snapshot they already hold. An empty list means the thread has no tasks. A non-empty list is the authoritative current snapshot and replaces any prior value.

- **AgentThreadDelta.title** (`str | None`) = `None`: Updated title of the agent thread.

### AgentThreadGoalRecord

```python
class roboto.ai.core.record.AgentThreadGoalRecord(/, **data: Any)
```

`from roboto.ai.agent_thread import AgentThreadGoalRecord`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L289-L338)

Bases: `pydantic.BaseModel`

Customer-visible read shape of a goal declared on an agent thread.

**Parameters**

- **data** (`Any`)

**Attributes**

- **AgentThreadGoalRecord.achieve_tool_use_id** (`str | None`) = `None`: `tool_use_id` of the achieve-tool invocation associated with this goal. Populated by the turn runner on every achieve-tool attempt, so its final value depends on the goal's terminal status:

  - `ACHIEVED`: the `tool_use_id` of the successful invocation.
  - `FAILED`: the `tool_use_id` of the last attempted invocation, or `None` if the LLM never invoked the achieve-tool before the retry budget exhausted.
  - `PENDING`: `None` (or the most recent attempt so far).

  Use with [`AgentThread.goals`](/reference/python-sdk/roboto/ai/agent_thread/agent_thread#roboto.ai.agent_thread.agent_thread.AgentThread.goals) and the `GoalResult` accessor on the SDK wrapper to locate the exact `AgentToolUseContent` / `AgentToolResultContent` pair without scanning by tool name.

- **AgentThreadGoalRecord.concluded_at** (`datetime.datetime | None`) = `None`: Timestamp when the goal transitioned to a terminal state (ACHIEVED or FAILED). `None` while the goal is still PENDING.

- **AgentThreadGoalRecord.created** (`datetime.datetime`): Timestamp when the goal was registered.

- **AgentThreadGoalRecord.goal_data** (`dict[str, Any]`): The validated goal payload as JSON. Use [`to_agent_goal()`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadGoalRecord.to_agent_goal) to recover the typed model the caller declared.

- **AgentThreadGoalRecord.goal_type** (`str`): Discriminator selecting which `AgentGoal` model the [`goal_data`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadGoalRecord.goal_data) payload conforms to (e.g. `"dataset_summary"`).

- **AgentThreadGoalRecord.message_sequence_num** (`int`): Index in the thread's full messages list of the [`AgentRole.USER`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentRole.USER) message that declared this goal. Use to render goals adjacent to the turn they were attached to.

- **AgentThreadGoalRecord.status** (`roboto.ai.goals.AgentGoalStatus`): Current lifecycle state of the goal.

#### AgentThreadGoalRecord.to_agent_goal()

```python
def to_agent_goal() -> roboto.ai.goals.AgentGoal
```

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L330-L338)

Re-hydrate [`goal_data`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadGoalRecord.goal_data) into the typed [`AgentGoal`](/reference/python-sdk/roboto/ai/goals/types#roboto.ai.goals.types.AgentGoal) the caller declared.

**Returns**

- `roboto.ai.goals.AgentGoal`: The validated, discriminated [`AgentGoal`](/reference/python-sdk/roboto/ai/goals/types#roboto.ai.goals.types.AgentGoal) instance — for `"dataset_summary"` rows, a [`DatasetSummaryAgentGoal`](/reference/python-sdk/roboto/ai/goals/types#roboto.ai.goals.types.DatasetSummaryAgentGoal); for `"dataset_triage"` rows, a [`DatasetTriageGoal`](/reference/python-sdk/roboto/ai/goals/types#roboto.ai.goals.types.DatasetTriageGoal); etc.

### AgentThreadRecord

```python
class roboto.ai.core.record.AgentThreadRecord(/, **data: Any)
```

`from roboto.ai import AgentThreadRecord`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L341-L457)

Bases: `pydantic.BaseModel`

Complete record of an agent thread.

Contains all the persistent data for a thread including metadata, message history, and synchronization state.

**Parameters**

- **data** (`Any`)

**Attributes**

- **AgentThreadRecord.continuation_token** (`str`): Token used for incremental updates and synchronization.

- **AgentThreadRecord.created** (`datetime.datetime`): Timestamp when this agent thread was created.

- **AgentThreadRecord.created_by** (`str`): User ID of the person who created this agent thread.

- **AgentThreadRecord.created_by_principal** (`str | None`) = `None`: Serialized [`RobotoPrincipal`](/reference/python-sdk/roboto/principal#roboto.principal.RobotoPrincipal) (`"ptype:id"`) that started this thread, e.g. `"user:jo@example.com"` or `"invocation:iv_123"`. Unlike [`created_by`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadRecord.created_by), this preserves whether the thread was driven by a person, a device, or an action invocation. `None` on threads created before this field existed.

- **AgentThreadRecord.created_from_agent_id** (`str | None`) = `None`: If this thread was started via the agent launch flow, the id of the agent that produced it. `None` for threads started directly through `POST /v1/ai/threads`. Forks do not inherit this field — a fork is its own thread.

- **AgentThreadRecord.created_from_trigger_id** (`str | None`) = `None`: If a trigger's `start_agent` target launched this thread, the id of that trigger. `None` for every other thread, including one launched from the same agent by a person. Set alongside [`created_from_agent_id`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadRecord.created_from_agent_id), which names the agent; this names what decided to run it. Forks do not inherit this field — a fork is its own thread.

- **AgentThreadRecord.forked_from_message_sequence_num** (`int | None`) = `None`: Message sequence number in the source thread that this fork was taken from.

  Populated in tandem with `forked_from_thread_id`; both are `None` for threads that were not created as a fork.

- **AgentThreadRecord.forked_from_thread_id** (`str | None`) = `None`: If this thread was forked, the id of the source thread. `None` otherwise.

  Deserialization also accepts the legacy `forked_from_session_id` spelling for backward compatibility.

- **AgentThreadRecord.goals** (`list[AgentThreadGoalRecord] | None`) = `None`: Goals declared across this thread's turns, ordered by the turn that declared them. `None` means goals were not loaded for this record; an empty list means they were loaded but the thread never declared any.

- **AgentThreadRecord.messages** (`list[AgentMessage]`) = `None`: Complete list of messages in the conversation.

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

- **AgentThreadRecord.model_profile** (`str | None`) = `None`: Model profile used for this agent thread (e.g., 'standard', 'advanced').

- **AgentThreadRecord.org_id** (`str`): Organization ID that owns this agent thread.

- **AgentThreadRecord.origin** (`ThreadOrigin | None`) = `None`: The surface that owns this thread.

  Set by Roboto when the thread is created; it cannot be supplied by a caller. A thread owned by a surface outside Roboto refuses new messages over the API, raising [`RobotoThreadReadOnlyException`](/reference/python-sdk/roboto/exceptions/domain#roboto.exceptions.domain.RobotoThreadReadOnlyException); reading, cancelling, and rating it stay open, and a fork does not inherit the origin, so the copy is writable.

  `None` on threads created before this field existed, and equivalent to [`ThreadOrigin.API`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.ThreadOrigin.API) — every surface that predates the field was Roboto's own. It stays nullable until those rows are backfilled.

- **AgentThreadRecord.pinned_at** (`datetime.datetime | None`) = `None`: When the calling user pinned this thread, or `None` if they have not.

  A pin is a personal bookmark, so two users reading the same thread see different values here. Pin and unpin through [`roboto.ai.agent_thread.AgentThread.set_pinned()`](/reference/python-sdk/roboto/ai/agent_thread/agent_thread#roboto.ai.agent_thread.agent_thread.AgentThread.set_pinned). Only `GET /v1/ai/threads` and `POST /v1/ai/threads/search` report it; reads of a single thread leave it `None` whatever the pin state.

- **AgentThreadRecord.status** (`AgentThreadStatus`): Current status of this agent thread.

- **AgentThreadRecord.tasks** (`list[roboto.ai.core.task.AgentTask] | None`) = `None`: The thread's task list, ordered by [`AgentTask.position`](/reference/python-sdk/roboto/ai/core/task#roboto.ai.core.task.AgentTask.position). `None` means tasks were not loaded for this record; an empty list means they were loaded but the thread has none.

- **AgentThreadRecord.thread_id** (`str`) = `None`: Unique identifier for this agent thread.

  Deserialization also accepts the legacy `session_id` and `chat_id` spellings for backward compatibility; the canonical attribute name is `thread_id`.

- **AgentThreadRecord.title** (`str | None`) = `None`: Title of this agent thread.

- **AgentThreadRecord.visibility** (`ThreadVisibility`): Who can read this thread. `PRIVATE` (the default) restricts reads to the [`created_by`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadRecord.created_by) user and Roboto admins; `ORG` opens the thread to every member of [`org_id`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadRecord.org_id).

### AgentThreadStatus

```python
class roboto.ai.core.record.AgentThreadStatus
```

`from roboto.ai.agent_thread import AgentThreadStatus`

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

Bases: `roboto.compat.StrEnum`

Enumeration of possible agent thread states.

Tracks the overall status of an agent thread from creation to termination.

**Attributes**

- **AgentThreadStatus.CLIENT_TOOL_TURN** = `'client_tool_turn'`: Client must execute pending tool uses and submit results.
- **AgentThreadStatus.GOALS_FAILED** = `'goals_failed'`: The agent runner exhausted its corrective re-prompt budget without achieving every declared goal for the most-recent turn. Signals to clients that the thread needs human intervention before it can continue.
- **AgentThreadStatus.NOT_STARTED** = `'not_started'`: Thread has been created but no messages have been sent.
- **AgentThreadStatus.ROBOTO_TURN** = `'roboto_turn'`: Roboto is generating a message.
- **AgentThreadStatus.USER_TURN** = `'user_turn'`: User has the turn to send a message.

### CLIENT_TOOL_NAME_PREFIX

```python
roboto.ai.core.record.CLIENT_TOOL_NAME_PREFIX = 'client_'
```

`from roboto.ai.core.record import CLIENT_TOOL_NAME_PREFIX`

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

Required prefix for every client-declared tool name.

Distinguishes client tools from server-side tools at every layer (API, SDK, UI, Bedrock toolConfig) without ambiguity. Underscore is used rather than a colon so the resulting name still matches Bedrock's Converse `toolSpec.name` pattern (`^[a-zA-Z][a-zA-Z0-9_]*$`).

### ClientToolSpec

```python
class roboto.ai.core.record.ClientToolSpec(/, **data: Any)
```

`from roboto import ClientToolSpec`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L199-L227)

Bases: `pydantic.BaseModel`

Declarative specification for a client-side tool.

Unlike AgentTool (which is an ABC with a \_\_call\_\_ method for server-side execution), ClientToolSpec is a plain data model. The backend includes it in the LLM's tool list but never executes it — the client is responsible for execution and submitting the result.

**Parameters**

- **data** (`Any`)

**Attributes**

- **ClientToolSpec.description** (`str`)
- **ClientToolSpec.input_schema** (`dict[str, Any]`)
- **ClientToolSpec.name** (`str`)

### ModelProfileResponse

```python
class roboto.ai.core.record.ModelProfileResponse(/, **data: Any)
```

`from roboto.ai.core import ModelProfileResponse`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L110-L123)

Bases: `pydantic.BaseModel`

Metadata about an available model profile, returned by the API.

**Parameters**

- **data** (`Any`)

**Attributes**

- **ModelProfileResponse.description** (`str`): Short description of the profile's characteristics.
- **ModelProfileResponse.id** (`str`): Profile identifier, e.g. 'standard' or 'advanced'.
- **ModelProfileResponse.is_default** (`bool`) = `False`: Whether this profile is selected by default for new threads.
- **ModelProfileResponse.label** (`str`): Human-readable display label.

### ThreadOrigin

```python
class roboto.ai.core.record.ThreadOrigin
```

`from roboto.ai.agent_thread import ThreadOrigin`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L49-L67)

Bases: `roboto.compat.StrEnum`

The surface an [`AgentThreadRecord`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadRecord) was started from, and the one that owns it.

Distinct from [`AgentThreadRecord.created_by_principal`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadRecord.created_by_principal), which records *who* started a thread. This records where the conversation lives, which is what decides whether it can be added to over the API.

Import as [`roboto.ai.agent_thread.ThreadOrigin`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.ThreadOrigin).

**Attributes**

- **ThreadOrigin.API** = `'api'`: Started through Roboto itself -- the web app, the CLI, the SDK, or a direct REST call.

  These surfaces read the thread back from Roboto rather than mirroring it somewhere else, so there is nothing for a new turn to fall out of sync with and the thread stays writable.

- **ThreadOrigin.SLACK** = `'slack'`: Started by mentioning @Roboto in Slack, and mirrored into that Slack conversation.

### ThreadVisibility

```python
class roboto.ai.core.record.ThreadVisibility
```

`from roboto.ai.agent_thread import ThreadVisibility`

[Source](https://github.com/roboto-ai/roboto-python-sdk/blob/main/src/roboto/ai/core/record.py#L70-L94)

Bases: `roboto.compat.StrEnum`

Read-scope for an [`AgentThreadRecord`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.AgentThreadRecord).

Set when the thread is created, and changed afterwards only by the thread's creator, via [`roboto.ai.agent_thread.AgentThread.set_visibility()`](/reference/python-sdk/roboto/ai/agent_thread/agent_thread#roboto.ai.agent_thread.agent_thread.AgentThread.set_visibility) (`POST /v1/ai/threads/<thread_id>/visibility`). Roboto admins read every thread but cannot re-scope one they did not create.

Import as [`roboto.ai.agent_thread.ThreadVisibility`](/reference/python-sdk/roboto/ai/core/record#roboto.ai.core.record.ThreadVisibility).

**Attributes**

- **ThreadVisibility.ORG** = `'org'`: Any member of the thread's organization (and Roboto admins) may read the thread.

  Default for threads produced by the agent launch flow, since agents exist to share workflows across teammates. Forks of an `ORG` thread do not inherit visibility — every fork lands as `PRIVATE`.

- **ThreadVisibility.PRIVATE** = `'private'`: Only the creating user (and Roboto admins) may read the thread.

  Default for threads created via `POST /v1/ai/threads` so an in-flight experiment does not leak to the rest of the org until the caller opts in.
