archastro.platform.types.threads

  1# Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License.
  2# This file is auto-generated by @archastro/sdk-generator. Do not edit.
  3# Content hash: 60f997dab0c6
  4
  5from datetime import datetime
  6from typing import Any, Literal
  7
  8from pydantic import BaseModel, Field
  9
 10from .common import Acl, Agent, Attachment, Message
 11from .users import User
 12
 13
 14class ThreadSettings(BaseModel):
 15    """
 16    Configuration settings for a thread that control AI agent behavior and other thread-level preferences.
 17    """
 18
 19    agent_enabled: bool | None = Field(
 20        default=None,
 21        description="Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured. `null` when a client explicitly cleared the setting.",
 22    )
 23
 24
 25class Thread(BaseModel):
 26    """
 27    A chat thread, representing a conversation channel that can be owned by a user, team, or agent and may contain messages, participants, and AI agent activity.
 28    """
 29
 30    agent_user: str | None = Field(
 31        default=None,
 32        description="ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads.",
 33    )
 34    created_at: str | None = Field(
 35        default=None, description="When the thread was created (ISO 8601)."
 36    )
 37    creator: str | dict[str, Any] | None = Field(
 38        default=None,
 39        description="User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown.",
 40    )
 41    description: str | None = Field(
 42        default=None,
 43        description="Optional description or purpose statement for the thread. `null` if not set.",
 44    )
 45    id: str = Field(..., description="Thread ID (`thr_...`).")
 46    is_channel: bool | None = Field(
 47        default=None,
 48        description="Whether this thread operates as a channel a multi-member broadcast-style conversation.",
 49    )
 50    is_default: bool | None = Field(
 51        default=None,
 52        description="Whether this is the default thread for its owner. Each user or team has at most one default thread.",
 53    )
 54    is_transient: bool | None = Field(
 55        default=None,
 56        description="Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.",
 57    )
 58    is_unlisted: bool | None = Field(
 59        default=None,
 60        description="Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.",
 61    )
 62    key: str | None = Field(
 63        default=None,
 64        description="Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set.",
 65    )
 66    kind: str | None = Field(
 67        default=None,
 68        description='Thread subtype: `"standard"` for ordinary threads, `"personal"` for a user-and-owned-agents roster, `"slack_mirror"` for the membership-strict mirror of a Slack channel, or `"slashwork_mirror"` for the membership-strict mirror of a Slashwork group. `personal` is an explicit user-thread creation option; mirror kinds are server-derived.',
 69    )
 70    last_activity: str | None = Field(
 71        default=None,
 72        description="When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment.",
 73    )
 74    last_message_preview: str | None = Field(
 75        default=None,
 76        description="Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.",
 77    )
 78    last_message_sender: str | None = Field(
 79        default=None,
 80        description="Display name of the sender of the most recent message the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment.",
 81    )
 82    metadata: dict[str, Any] | None = Field(
 83        default=None,
 84        description="Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set.",
 85    )
 86    muted: bool | None = Field(
 87        default=None,
 88        description="Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery.",
 89    )
 90    org: str | None = Field(
 91        default=None,
 92        description="ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context.",
 93    )
 94    parent_message: Message | None = Field(
 95        default=None,
 96        description="The message that spawned this thread as a sub-thread. `null` for top-level threads.",
 97    )
 98    participant: list[str] | None = Field(
 99        default=None,
100        description="Array of participant user IDs (`usr_...`) who are members of this thread.",
101    )
102    participants: list[User] | None = Field(
103        default=None,
104        description="Expanded participant user objects for each member of this thread. Populated only when the association is loaded.",
105    )
106    participating_actor: list[str] | None = Field(
107        default=None,
108        description="Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.",
109    )
110    participating_agents: list[Agent] | None = Field(
111        default=None,
112        description="Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.",
113    )
114    role: str | None = Field(
115        default=None,
116        description='The authenticated user\'s membership role in this thread, e.g. `"owner"`, `"member"`, or `"viewer"`. `null` if the user is not a member.',
117    )
118    sandbox: str | None = Field(
119        default=None,
120        description="ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads.",
121    )
122    settings: ThreadSettings | None = Field(
123        default=None,
124        description="Per-thread configuration settings controlling AI agent behavior for this thread.",
125    )
126    slug: str | None = Field(
127        default=None,
128        description="URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned.",
129    )
130    sub_threads: list[dict[str, Any]] | None = Field(
131        default=None,
132        description="Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.",
133    )
134    tags: list[str] | None = Field(
135        default=None,
136        description='Status tags on the thread (e.g. `"blocked"`, `"needs-review"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set.',
137    )
138    team: str | None = Field(
139        default=None,
140        description="ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads.",
141    )
142    title: str | None = Field(
143        default=None,
144        description="Human-readable name of the thread. `null` if no title has been set.",
145    )
146    ttl: str | None = Field(
147        default=None,
148        description="Offset-free expiry timestamp after which the thread may be automatically cleaned up. `null` if the thread does not expire.",
149    )
150    unread_count: int | None = Field(
151        default=None,
152        description="Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.",
153    )
154    updated_at: str | None = Field(
155        default=None, description="When the thread was last modified (ISO 8601)."
156    )
157    user: str | None = Field(
158        default=None,
159        description="ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads.",
160    )
161    visibility: Literal["team", "restricted", "private"] = Field(
162        ...,
163        description="Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access.",
164    )
165
166
167class ThreadMessage(BaseModel):
168    """
169    A single message posted to a thread, as seen from the developer portal. Includes sender information, optional attachments, and scoping identifiers.
170    """
171
172    acl: Acl | None = Field(
173        default=None,
174        description="Access control list for private messages. Only returned to resource owners (and privileged/org-admin viewers); `null` otherwise.",
175    )
176    admin: dict[str, Any] | None = Field(
177        default=None,
178        description="Admin-only diagnostic metadata for the message, including execution trajectory details. Only present in developer portal responses.",
179    )
180    agent: str | None = Field(
181        default=None,
182        description="Agent ID (`agt_...`) associated with the message. `null` if not agent-scoped.",
183    )
184    agent_mode: Literal["cli", "embedded"] | None = Field(
185        default=None,
186        description="Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.",
187    )
188    app: str | None = Field(
189        default=None, description="App ID (`app_...`) that the message belongs to."
190    )
191    attachments: list[Attachment] | None = Field(
192        default=None,
193        description="Files or media attached to the message. Empty array if no attachments are present.",
194    )
195    content: str | None = Field(
196        default=None,
197        description="Text content of the message. `null` if the message contains only attachments.",
198    )
199    created_at: datetime | None = Field(
200        default=None, description="When the message was posted to the thread (ISO 8601)."
201    )
202    id: str = Field(..., description="Message ID (`msg_...`).")
203    metadata: dict[str, Any] | None = Field(
204        default=None,
205        description="Key-value metadata attached to the message. Always present; defaults to an empty object. The `metadata` query parameter filters on this same object, so a caller can read back the field it selects on.",
206    )
207    org: str | None = Field(
208        default=None,
209        description="Organization ID (`org_...`) this message is scoped to. `null` if not org-scoped.",
210    )
211    root_message_id: str | None = Field(
212        default=None,
213        description="ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.",
214    )
215    sandbox: str | None = Field(
216        default=None,
217        description="Sandbox ID (`dsb_...`) this message is scoped to. `null` if not sandbox-scoped.",
218    )
219    sender: str | None = Field(
220        default=None,
221        description="Public ID of the sender (e.g. `usr_...` or `agt_...`). `null` for system-generated messages.",
222    )
223    sender_name: str | None = Field(
224        default=None, description="Display name of the message sender. `null` if unavailable."
225    )
226    sender_type: str | None = Field(
227        default=None,
228        description='Category of entity that sent the message. One of `"user"`, `"agent"`, or `"system"`.',
229    )
230    team: str | None = Field(
231        default=None,
232        description="Team ID (`tea_...`) associated with the message. `null` if not team-scoped.",
233    )
234    type: str | None = Field(
235        default=None,
236        description="Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.",
237    )
238    user: str | None = Field(
239        default=None,
240        description="User ID (`usr_...`) associated with the message. `null` if not user-scoped.",
241    )
242    visibility: Literal["default", "private"] | None = Field(
243        default=None,
244        description="Message-level visibility. `default` follows thread membership; `private` is limited to the sender and ACL `read` grantees.",
245    )
246
247
248class ThreadReadStatus(BaseModel):
249    """
250    The read status of a thread for a specific user, indicating how far they have read and how many messages remain unread.
251    """
252
253    last_read_message: str | None = Field(
254        default=None,
255        description="Message ID (`msg_...`) of the last message the user has read in this thread. `null` if the user has never read any message in the thread.",
256    )
257    thread: str = Field(..., description="Thread ID (`thr_...`) that this read status belongs to.")
258    unread_count: int = Field(
259        ..., description="Number of messages in the thread that the user has not yet read."
260    )
class ThreadSettings(pydantic.main.BaseModel):
15class ThreadSettings(BaseModel):
16    """
17    Configuration settings for a thread that control AI agent behavior and other thread-level preferences.
18    """
19
20    agent_enabled: bool | None = Field(
21        default=None,
22        description="Whether the AI agent is active for this thread. `true` enables AI responses; `false` disables them. Defaults to `true` when settings have not been explicitly configured. `null` when a client explicitly cleared the setting.",
23    )

Configuration settings for a thread that control AI agent behavior and other thread-level preferences.

agent_enabled: bool | None = None

Whether the AI agent is active for this thread. true enables AI responses; false disables them. Defaults to true when settings have not been explicitly configured. null when a client explicitly cleared the setting.

class Thread(pydantic.main.BaseModel):
 26class Thread(BaseModel):
 27    """
 28    A chat thread, representing a conversation channel that can be owned by a user, team, or agent and may contain messages, participants, and AI agent activity.
 29    """
 30
 31    agent_user: str | None = Field(
 32        default=None,
 33        description="ID of the agent that owns this thread (`agt_...`). `null` for user-owned or team-owned threads.",
 34    )
 35    created_at: str | None = Field(
 36        default=None, description="When the thread was created (ISO 8601)."
 37    )
 38    creator: str | dict[str, Any] | None = Field(
 39        default=None,
 40        description="User who created this thread. Returns a user ID (`usr_...`) by default, or an expanded user object when the association is loaded. `null` if the creator is unknown.",
 41    )
 42    description: str | None = Field(
 43        default=None,
 44        description="Optional description or purpose statement for the thread. `null` if not set.",
 45    )
 46    id: str = Field(..., description="Thread ID (`thr_...`).")
 47    is_channel: bool | None = Field(
 48        default=None,
 49        description="Whether this thread operates as a channel a multi-member broadcast-style conversation.",
 50    )
 51    is_default: bool | None = Field(
 52        default=None,
 53        description="Whether this is the default thread for its owner. Each user or team has at most one default thread.",
 54    )
 55    is_transient: bool | None = Field(
 56        default=None,
 57        description="Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.",
 58    )
 59    is_unlisted: bool | None = Field(
 60        default=None,
 61        description="Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.",
 62    )
 63    key: str | None = Field(
 64        default=None,
 65        description="Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. `null` if not set.",
 66    )
 67    kind: str | None = Field(
 68        default=None,
 69        description='Thread subtype: `"standard"` for ordinary threads, `"personal"` for a user-and-owned-agents roster, `"slack_mirror"` for the membership-strict mirror of a Slack channel, or `"slashwork_mirror"` for the membership-strict mirror of a Slashwork group. `personal` is an explicit user-thread creation option; mirror kinds are server-derived.',
 70    )
 71    last_activity: str | None = Field(
 72        default=None,
 73        description="When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); `null` on endpoints that don't compute activity enrichment.",
 74    )
 75    last_message_preview: str | None = Field(
 76        default=None,
 77        description="Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside `last_activity`; `null` when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.",
 78    )
 79    last_message_sender: str | None = Field(
 80        default=None,
 81        description="Display name of the sender of the most recent message the same message `last_message_preview` snippets. Populated on thread list endpoints; `null` when the thread has no messages or the endpoint doesn't compute activity enrichment.",
 82    )
 83    metadata: dict[str, Any] | None = Field(
 84        default=None,
 85        description="Arbitrary key-value metadata attached to the thread. Shape is application-defined; `null` if no metadata has been set.",
 86    )
 87    muted: bool | None = Field(
 88        default=None,
 89        description="Whether the authenticated user has muted notifications for this thread. `true` suppresses all notification delivery.",
 90    )
 91    org: str | None = Field(
 92        default=None,
 93        description="ID of the organization this thread belongs to (`org_...`). `null` for threads outside an org context.",
 94    )
 95    parent_message: Message | None = Field(
 96        default=None,
 97        description="The message that spawned this thread as a sub-thread. `null` for top-level threads.",
 98    )
 99    participant: list[str] | None = Field(
100        default=None,
101        description="Array of participant user IDs (`usr_...`) who are members of this thread.",
102    )
103    participants: list[User] | None = Field(
104        default=None,
105        description="Expanded participant user objects for each member of this thread. Populated only when the association is loaded.",
106    )
107    participating_actor: list[str] | None = Field(
108        default=None,
109        description="Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.",
110    )
111    participating_agents: list[Agent] | None = Field(
112        default=None,
113        description="Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.",
114    )
115    role: str | None = Field(
116        default=None,
117        description='The authenticated user\'s membership role in this thread, e.g. `"owner"`, `"member"`, or `"viewer"`. `null` if the user is not a member.',
118    )
119    sandbox: str | None = Field(
120        default=None,
121        description="ID of the developer sandbox this thread is scoped to (`dsb_...`). `null` for production threads.",
122    )
123    settings: ThreadSettings | None = Field(
124        default=None,
125        description="Per-thread configuration settings controlling AI agent behavior for this thread.",
126    )
127    slug: str | None = Field(
128        default=None,
129        description="URL-safe slug for the thread, used in human-readable permalinks. `null` if not assigned.",
130    )
131    sub_threads: list[dict[str, Any]] | None = Field(
132        default=None,
133        description="Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.",
134    )
135    tags: list[str] | None = Field(
136        default=None,
137        description='Status tags on the thread (e.g. `"blocked"`, `"needs-review"`). Edited by any thread participant via the `/threads/:thread/tags` endpoints and filterable on the thread list endpoints. Empty array if none set.',
138    )
139    team: str | None = Field(
140        default=None,
141        description="ID of the team that owns this thread (`team_...`). `null` for user-owned or agent-owned threads.",
142    )
143    title: str | None = Field(
144        default=None,
145        description="Human-readable name of the thread. `null` if no title has been set.",
146    )
147    ttl: str | None = Field(
148        default=None,
149        description="Offset-free expiry timestamp after which the thread may be automatically cleaned up. `null` if the thread does not expire.",
150    )
151    unread_count: int | None = Field(
152        default=None,
153        description="Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.",
154    )
155    updated_at: str | None = Field(
156        default=None, description="When the thread was last modified (ISO 8601)."
157    )
158    user: str | None = Field(
159        default=None,
160        description="ID of the user who owns this thread (`usr_...`). `null` for team-owned or agent-owned threads.",
161    )
162    visibility: Literal["team", "restricted", "private"] = Field(
163        ...,
164        description="Who can read the thread: `team` for every owning-team member, `restricted` for team-readable threads with an explicit roster, or `private` for roster-only access.",
165    )

A chat thread, representing a conversation channel that can be owned by a user, team, or agent and may contain messages, participants, and AI agent activity.

agent_user: str | None = None

ID of the agent that owns this thread (agt_...). null for user-owned or team-owned threads.

created_at: str | None = None

When the thread was created (ISO 8601).

creator: str | dict[str, typing.Any] | None = None

User who created this thread. Returns a user ID (usr_...) by default, or an expanded user object when the association is loaded. null if the creator is unknown.

description: str | None = None

Optional description or purpose statement for the thread. null if not set.

id: str = PydanticUndefined

Thread ID (thr_...).

is_channel: bool | None = None

Whether this thread operates as a channel a multi-member broadcast-style conversation.

is_default: bool | None = None

Whether this is the default thread for its owner. Each user or team has at most one default thread.

is_transient: bool | None = None

Whether this thread is ephemeral and may be deleted automatically after a period of inactivity or when its TTL expires.

is_unlisted: bool | None = None

Whether this thread is hidden from public discovery. Unlisted threads are accessible only to direct participants.

key: str | None = None

Application-defined stable key that uniquely identifies the thread within its scope. Useful for idempotent creation. null if not set.

kind: str | None = None

Thread subtype: "standard" for ordinary threads, "personal" for a user-and-owned-agents roster, "slack_mirror" for the membership-strict mirror of a Slack channel, or "slashwork_mirror" for the membership-strict mirror of a Slashwork group. personal is an explicit user-thread creation option; mirror kinds are server-derived.

last_activity: str | None = None

When the most recent message was posted in this thread, falling back to the thread's creation time if it has no messages. Always populated on thread list endpoints (which order by it, after default threads); null on endpoints that don't compute activity enrichment.

last_message_preview: str | None = None

Single-line snippet of the most recent message's text content (first non-empty line, truncated to 140 characters). Populated on thread list endpoints alongside last_activity; null when the thread has no messages, the latest message has no text content (e.g. attachment-only), or the endpoint doesn't compute activity enrichment.

last_message_sender: str | None = None

Display name of the sender of the most recent message the same message last_message_preview snippets. Populated on thread list endpoints; null when the thread has no messages or the endpoint doesn't compute activity enrichment.

metadata: dict[str, typing.Any] | None = None

Arbitrary key-value metadata attached to the thread. Shape is application-defined; null if no metadata has been set.

muted: bool | None = None

Whether the authenticated user has muted notifications for this thread. true suppresses all notification delivery.

org: str | None = None

ID of the organization this thread belongs to (org_...). null for threads outside an org context.

parent_message: archastro.platform.types.common.Message | None = None

The message that spawned this thread as a sub-thread. null for top-level threads.

participant: list[str] | None = None

Array of participant user IDs (usr_...) who are members of this thread.

participants: list[archastro.platform.types.users.User] | None = None

Expanded participant user objects for each member of this thread. Populated only when the association is loaded.

participating_actor: list[str] | None = None

Composite actor identifiers for all participants currently active in this thread. Present only when actor enrichment is requested.

participating_agents: list[archastro.platform.types.common.Agent] | None = None

Expanded agent objects for all agents participating in this thread. Present only when agent enrichment is requested.

role: str | None = None

The authenticated user's membership role in this thread, e.g. "owner", "member", or "viewer". null if the user is not a member.

sandbox: str | None = None

ID of the developer sandbox this thread is scoped to (dsb_...). null for production threads.

settings: ThreadSettings | None = None

Per-thread configuration settings controlling AI agent behavior for this thread.

slug: str | None = None

URL-safe slug for the thread, used in human-readable permalinks. null if not assigned.

sub_threads: list[dict[str, typing.Any]] | None = None

Threads that are nested under this thread as replies to a parent message. Present only when sub-thread enrichment is requested.

tags: list[str] | None = None

Status tags on the thread (e.g. "blocked", "needs-review"). Edited by any thread participant via the /threads/:thread/tags endpoints and filterable on the thread list endpoints. Empty array if none set.

team: str | None = None

ID of the team that owns this thread (team_...). null for user-owned or agent-owned threads.

title: str | None = None

Human-readable name of the thread. null if no title has been set.

ttl: str | None = None

Offset-free expiry timestamp after which the thread may be automatically cleaned up. null if the thread does not expire.

unread_count: int | None = None

Number of messages in this thread that the authenticated user has not yet read. Present only when read-state enrichment is requested.

updated_at: str | None = None

When the thread was last modified (ISO 8601).

user: str | None = None

ID of the user who owns this thread (usr_...). null for team-owned or agent-owned threads.

visibility: Literal['team', 'restricted', 'private'] = PydanticUndefined

Who can read the thread: team for every owning-team member, restricted for team-readable threads with an explicit roster, or private for roster-only access.

class ThreadMessage(pydantic.main.BaseModel):
168class ThreadMessage(BaseModel):
169    """
170    A single message posted to a thread, as seen from the developer portal. Includes sender information, optional attachments, and scoping identifiers.
171    """
172
173    acl: Acl | None = Field(
174        default=None,
175        description="Access control list for private messages. Only returned to resource owners (and privileged/org-admin viewers); `null` otherwise.",
176    )
177    admin: dict[str, Any] | None = Field(
178        default=None,
179        description="Admin-only diagnostic metadata for the message, including execution trajectory details. Only present in developer portal responses.",
180    )
181    agent: str | None = Field(
182        default=None,
183        description="Agent ID (`agt_...`) associated with the message. `null` if not agent-scoped.",
184    )
185    agent_mode: Literal["cli", "embedded"] | None = Field(
186        default=None,
187        description="Local agent execution mode for this message. One of `cli`, `embedded`, or `null` when the message was not created by a local agent execution path.",
188    )
189    app: str | None = Field(
190        default=None, description="App ID (`app_...`) that the message belongs to."
191    )
192    attachments: list[Attachment] | None = Field(
193        default=None,
194        description="Files or media attached to the message. Empty array if no attachments are present.",
195    )
196    content: str | None = Field(
197        default=None,
198        description="Text content of the message. `null` if the message contains only attachments.",
199    )
200    created_at: datetime | None = Field(
201        default=None, description="When the message was posted to the thread (ISO 8601)."
202    )
203    id: str = Field(..., description="Message ID (`msg_...`).")
204    metadata: dict[str, Any] | None = Field(
205        default=None,
206        description="Key-value metadata attached to the message. Always present; defaults to an empty object. The `metadata` query parameter filters on this same object, so a caller can read back the field it selects on.",
207    )
208    org: str | None = Field(
209        default=None,
210        description="Organization ID (`org_...`) this message is scoped to. `null` if not org-scoped.",
211    )
212    root_message_id: str | None = Field(
213        default=None,
214        description="ID of the root message in this reply chain (`msg_...`). `null` for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.",
215    )
216    sandbox: str | None = Field(
217        default=None,
218        description="Sandbox ID (`dsb_...`) this message is scoped to. `null` if not sandbox-scoped.",
219    )
220    sender: str | None = Field(
221        default=None,
222        description="Public ID of the sender (e.g. `usr_...` or `agt_...`). `null` for system-generated messages.",
223    )
224    sender_name: str | None = Field(
225        default=None, description="Display name of the message sender. `null` if unavailable."
226    )
227    sender_type: str | None = Field(
228        default=None,
229        description='Category of entity that sent the message. One of `"user"`, `"agent"`, or `"system"`.',
230    )
231    team: str | None = Field(
232        default=None,
233        description="Team ID (`tea_...`) associated with the message. `null` if not team-scoped.",
234    )
235    type: str | None = Field(
236        default=None,
237        description="Optional client-defined classification for the message (for example `note` or `status`). Free-form string up to 64 characters. The value `system` is reserved for platform-authored messages and cannot be set by clients. `null` when unset.",
238    )
239    user: str | None = Field(
240        default=None,
241        description="User ID (`usr_...`) associated with the message. `null` if not user-scoped.",
242    )
243    visibility: Literal["default", "private"] | None = Field(
244        default=None,
245        description="Message-level visibility. `default` follows thread membership; `private` is limited to the sender and ACL `read` grantees.",
246    )

A single message posted to a thread, as seen from the developer portal. Includes sender information, optional attachments, and scoping identifiers.

Access control list for private messages. Only returned to resource owners (and privileged/org-admin viewers); null otherwise.

admin: dict[str, typing.Any] | None = None

Admin-only diagnostic metadata for the message, including execution trajectory details. Only present in developer portal responses.

agent: str | None = None

Agent ID (agt_...) associated with the message. null if not agent-scoped.

agent_mode: Optional[Literal['cli', 'embedded']] = None

Local agent execution mode for this message. One of cli, embedded, or null when the message was not created by a local agent execution path.

app: str | None = None

App ID (app_...) that the message belongs to.

attachments: list[archastro.platform.types.common.Attachment] | None = None

Files or media attached to the message. Empty array if no attachments are present.

content: str | None = None

Text content of the message. null if the message contains only attachments.

created_at: datetime.datetime | None = None

When the message was posted to the thread (ISO 8601).

id: str = PydanticUndefined

Message ID (msg_...).

metadata: dict[str, typing.Any] | None = None

Key-value metadata attached to the message. Always present; defaults to an empty object. The metadata query parameter filters on this same object, so a caller can read back the field it selects on.

org: str | None = None

Organization ID (org_...) this message is scoped to. null if not org-scoped.

root_message_id: str | None = None

ID of the root message in this reply chain (msg_...). null for a top-level message. The value is persisted when the reply is created, so callers can correlate a multi-turn session without walking parent messages.

sandbox: str | None = None

Sandbox ID (dsb_...) this message is scoped to. null if not sandbox-scoped.

sender: str | None = None

Public ID of the sender (e.g. usr_... or agt_...). null for system-generated messages.

sender_name: str | None = None

Display name of the message sender. null if unavailable.

sender_type: str | None = None

Category of entity that sent the message. One of "user", "agent", or "system".

team: str | None = None

Team ID (tea_...) associated with the message. null if not team-scoped.

type: str | None = None

Optional client-defined classification for the message (for example note or status). Free-form string up to 64 characters. The value system is reserved for platform-authored messages and cannot be set by clients. null when unset.

user: str | None = None

User ID (usr_...) associated with the message. null if not user-scoped.

visibility: Optional[Literal['default', 'private']] = None

Message-level visibility. default follows thread membership; private is limited to the sender and ACL read grantees.

class ThreadReadStatus(pydantic.main.BaseModel):
249class ThreadReadStatus(BaseModel):
250    """
251    The read status of a thread for a specific user, indicating how far they have read and how many messages remain unread.
252    """
253
254    last_read_message: str | None = Field(
255        default=None,
256        description="Message ID (`msg_...`) of the last message the user has read in this thread. `null` if the user has never read any message in the thread.",
257    )
258    thread: str = Field(..., description="Thread ID (`thr_...`) that this read status belongs to.")
259    unread_count: int = Field(
260        ..., description="Number of messages in the thread that the user has not yet read."
261    )

The read status of a thread for a specific user, indicating how far they have read and how many messages remain unread.

last_read_message: str | None = None

Message ID (msg_...) of the last message the user has read in this thread. null if the user has never read any message in the thread.

thread: str = PydanticUndefined

Thread ID (thr_...) that this read status belongs to.

unread_count: int = PydanticUndefined

Number of messages in the thread that the user has not yet read.