archastro.platform.v1.resources.thread_messages

  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: b91c191bc4f5
  4
  5from __future__ import annotations
  6
  7from datetime import datetime
  8from typing import Any, Literal, Required, TypedDict
  9
 10from pydantic import BaseModel, Field
 11
 12from ...runtime.http_client import HttpClient, SyncHttpClient
 13from ...types.common import Message, PaginatedReplies
 14from ...types.threads import ThreadMessage
 15
 16
 17class ReactionCreateInput(TypedDict):
 18    "Add a reaction to a thread message"
 19
 20    emoji: str
 21    'Emoji character or shortcode to add as a reaction, e.g. `" "` or `":thumbsup:"`.'
 22
 23
 24class ThreadMessageReplaceInputAclAddItem(TypedDict, total=False):
 25    actions: Required[list[str]]
 26    'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.'
 27    principal: str | None
 28    'The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`.'
 29    principal_type: Required[str]
 30    'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
 31
 32
 33class ThreadMessageReplaceInputAclGrantsItem(TypedDict, total=False):
 34    actions: Required[list[str]]
 35    'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.'
 36    principal: str | None
 37    'The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`.'
 38    principal_type: Required[str]
 39    'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
 40
 41
 42class ThreadMessageReplaceInputAclRemoveItem(TypedDict, total=False):
 43    principal: str | None
 44    'The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`.'
 45    principal_type: Required[str]
 46    'The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
 47
 48
 49class ThreadMessageReplaceInputAcl(TypedDict, total=False):
 50    add: list[ThreadMessageReplaceInputAclAddItem] | None
 51    "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`."
 52    grants: list[ThreadMessageReplaceInputAclGrantsItem] | None
 53    "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`."
 54    remove: list[ThreadMessageReplaceInputAclRemoveItem] | None
 55    "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`."
 56
 57
 58class ThreadMessageReplaceInput(TypedDict, total=False):
 59    "Update a thread message"
 60
 61    acl: ThreadMessageReplaceInputAcl | None
 62    "Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged."
 63    content: str | None
 64    "Replacement text content for the message. Omit to leave the content unchanged."
 65    metadata: dict[str, Any] | None
 66    "Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped."
 67    type: str | None
 68    "Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected."
 69    visibility: Literal["default", "private"] | None
 70    "Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422."
 71
 72
 73class ReactionCreateResponseData(BaseModel):
 74    created_at: datetime | None = Field(
 75        default=None, description="When the reaction was added (ISO 8601)."
 76    )
 77    feedback_type: str | None = Field(
 78        default=None,
 79        description='Category of feedback. Currently `"emoji_reaction"` for emoji responses.',
 80    )
 81    id: str = Field(..., description="Reaction ID (`umf_...`).")
 82    message: str | None = Field(
 83        default=None, description="ID of the message this reaction is attached to (`msg_...`)."
 84    )
 85    payload: dict[str, Any] | None = Field(
 86        default=None,
 87        description='Structured data for the reaction. For `"emoji_reaction"` types, includes an `emoji` key with the Unicode emoji string.',
 88    )
 89    updated_at: datetime | None = Field(
 90        default=None, description="When the reaction was last modified (ISO 8601)."
 91    )
 92    user: str | None = Field(
 93        default=None, description="ID of the user who added the reaction (`usr_...`)."
 94    )
 95
 96
 97class ReactionCreateResponse(BaseModel):
 98    """
 99    Successful response
100    """
101
102    data: ReactionCreateResponseData = Field(..., description="Reaction object that was created.")
103
104
105class AsyncReactionResource:
106    def __init__(self, http: HttpClient):
107        self._http = http
108
109    async def remove(self, message: str) -> None:
110        """
111        Remove a reaction from a thread message
112        Removes the authenticated user's emoji reaction from the specified thread
113        message. The reaction is identified by the combination of the message ID and
114        the emoji; only the reaction belonging to the calling user is removed.
115        Returns 204 No Content on success. Returns 404 if no matching reaction
116        exists for the user and emoji on that message, or if the message itself
117        cannot be found. The authenticated user must have read access to the thread
118        containing the message.
119
120        Args:
121            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
122
123        Returns:
124            Empty response body. HTTP 204 No Content on success.
125        """
126        await self._http.request(f"/api/v1/thread_messages/{message}/reactions", method="DELETE")
127
128    async def create(self, message: str, input: ReactionCreateInput) -> ReactionCreateResponse:
129        """
130        Add a reaction to a thread message
131        Adds an emoji reaction to the specified thread message on behalf of the
132        authenticated user. If the user has already reacted to the message with the
133        same emoji, the request returns a 409 Conflict rather than creating a
134        duplicate.
135        The authenticated user must have read access to the thread containing the
136        message. If the thread belongs to a team, the user must be a member of
137        that team.
138
139        Args:
140            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
141            input: Request body.
142            input.emoji: Emoji character or shortcode to add as a reaction, e.g. `" "` or `":thumbsup:"`.
143
144        Returns:
145            Successful response
146        """
147        return await self._http.request(
148            f"/api/v1/thread_messages/{message}/reactions",
149            method="POST",
150            body=input,
151            response_type=ReactionCreateResponse,
152        )
153
154
155class AsyncThreadMessageResource:
156    def __init__(self, http: HttpClient):
157        self._http = http
158        self.reactions = AsyncReactionResource(http)
159
160    async def delete(self, message: str) -> None:
161        """
162        Delete a thread message
163        Permanently removes the specified message from its thread. This action
164        cannot be undone.
165        A message may be deleted by its author, an admin of the org the message
166        belongs to, an admin of the team that owns the thread, or the agent that
167        sent it. Service-to-service callers with elevated (`all_powerful`) scope
168        may delete any message in a thread they can access. Returns
169        `403 Forbidden` when the caller is not permitted to delete the message.
170
171        Args:
172            message: ID of the message to delete (`msg_...`).
173
174        Returns:
175            Empty body. The server responds with HTTP 204 No Content on success.
176        """
177        await self._http.request(f"/api/v1/thread_messages/{message}", method="DELETE")
178
179    async def get(self, message: str) -> ThreadMessage:
180        """
181        Retrieve a message
182        Returns a single message by its globally unique message ID. The authenticated
183        viewer must be able to read the message and its thread.
184        The response includes the message's content, sender information, and any
185        attachments that were loaded at creation time. For admin-authenticated
186        requests, an additional `admin` field is returned containing raw metadata
187        and the associated trajectory data (LLM input/output messages) if one exists.
188        A trajectory belongs to the agent response it produced, so `admin.trajectory`
189        is only populated on the response message. On the triggering user message
190        the trajectory is omitted and `admin.response_message` links to the agent
191        response (where the trajectory is shown), when a response exists.
192        If the message is not found or is not visible to the caller, a 404 is
193        returned.
194
195        Args:
196            message: Globally unique message ID (`msg_...`).
197
198        Returns:
199            The requested message, including its content, sender, and attachments.
200        """
201        return await self._http.request(
202            f"/api/v1/thread_messages/{message}",
203            response_type=ThreadMessage,
204        )
205
206    async def replace(self, message: str, input: ThreadMessageReplaceInput) -> Message:
207        """
208        Update a thread message
209        Edits an existing thread message and returns the updated message object.
210        A regular user may only edit messages they authored. Service-to-service
211        callers with elevated (`all_powerful`) scope may edit any accessible message
212        without an ownership check. Returns `403 Forbidden` when the caller does not
213        own the message.
214
215        Args:
216            message: ID of the message to update (`msg_...`).
217            input: Request body.
218            input.acl: Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged.
219            input.content: Replacement text content for the message. Omit to leave the content unchanged.
220            input.metadata: Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped.
221            input.type: Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected.
222            input.visibility: Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422.
223
224        Returns:
225            The updated message object.
226        """
227        return await self._http.request(
228            f"/api/v1/thread_messages/{message}",
229            method="PUT",
230            body=input,
231            response_type=Message,
232        )
233
234    async def replies(
235        self,
236        message: str,
237        *,
238        before_cursor: str | None = None,
239        after_cursor: str | None = None,
240        limit: int | None = None,
241        tree: bool | None = None,
242    ) -> PaginatedReplies:
243        """
244        List replies to a thread message
245        Returns a cursor-paginated list of reply messages for the specified thread
246        message. By default only direct (first-level) replies are returned. Set
247        `tree` to `true` to retrieve the full nested reply tree in a flat list,
248        ordered by creation time ascending.
249        The authenticated user must have access to the thread that contains the
250        message. If the message belongs to a team-scoped thread, the viewer is
251        automatically scoped to that team before the query executes.
252        Use `before_cursor` and `after_cursor` together with `limit` to page
253        through large reply threads. The `has_more` field in the response
254        indicates whether additional pages exist.
255
256        Args:
257            message: ID of the thread message to fetch replies for (`msg_...`).
258            before_cursor: Opaque pagination cursor. Returns replies created before this point. Obtain from `before_cursor` in a previous response.
259            after_cursor: Opaque pagination cursor. Returns replies created after this point. Obtain from `after_cursor` in a previous response.
260            limit: Maximum number of replies to return per page. Defaults to 20.
261            tree: When `true`, returns all replies in the nested reply tree (flattened). When `false` or omitted, returns only direct replies to the message.
262
263        Returns:
264            Cursor-paginated list of reply messages for the requested thread message.
265        """
266        query: dict[str, object] = {}
267        if before_cursor is not None:
268            query["before_cursor"] = before_cursor
269        if after_cursor is not None:
270            query["after_cursor"] = after_cursor
271        if limit is not None:
272            query["limit"] = limit
273        if tree is not None:
274            query["tree"] = tree
275        return await self._http.request(
276            f"/api/v1/thread_messages/{message}/replies",
277            query=query,
278            response_type=PaginatedReplies,
279        )
280
281
282class ReactionResource:
283    def __init__(self, http: SyncHttpClient):
284        self._http = http
285
286    def remove(self, message: str) -> None:
287        """
288        Remove a reaction from a thread message
289        Removes the authenticated user's emoji reaction from the specified thread
290        message. The reaction is identified by the combination of the message ID and
291        the emoji; only the reaction belonging to the calling user is removed.
292        Returns 204 No Content on success. Returns 404 if no matching reaction
293        exists for the user and emoji on that message, or if the message itself
294        cannot be found. The authenticated user must have read access to the thread
295        containing the message.
296
297        Args:
298            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
299
300        Returns:
301            Empty response body. HTTP 204 No Content on success.
302        """
303        self._http.request(f"/api/v1/thread_messages/{message}/reactions", method="DELETE")
304
305    def create(self, message: str, input: ReactionCreateInput) -> ReactionCreateResponse:
306        """
307        Add a reaction to a thread message
308        Adds an emoji reaction to the specified thread message on behalf of the
309        authenticated user. If the user has already reacted to the message with the
310        same emoji, the request returns a 409 Conflict rather than creating a
311        duplicate.
312        The authenticated user must have read access to the thread containing the
313        message. If the thread belongs to a team, the user must be a member of
314        that team.
315
316        Args:
317            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
318            input: Request body.
319            input.emoji: Emoji character or shortcode to add as a reaction, e.g. `" "` or `":thumbsup:"`.
320
321        Returns:
322            Successful response
323        """
324        return self._http.request(
325            f"/api/v1/thread_messages/{message}/reactions",
326            method="POST",
327            body=input,
328            response_type=ReactionCreateResponse,
329        )
330
331
332class ThreadMessageResource:
333    def __init__(self, http: SyncHttpClient):
334        self._http = http
335        self.reactions = ReactionResource(http)
336
337    def delete(self, message: str) -> None:
338        """
339        Delete a thread message
340        Permanently removes the specified message from its thread. This action
341        cannot be undone.
342        A message may be deleted by its author, an admin of the org the message
343        belongs to, an admin of the team that owns the thread, or the agent that
344        sent it. Service-to-service callers with elevated (`all_powerful`) scope
345        may delete any message in a thread they can access. Returns
346        `403 Forbidden` when the caller is not permitted to delete the message.
347
348        Args:
349            message: ID of the message to delete (`msg_...`).
350
351        Returns:
352            Empty body. The server responds with HTTP 204 No Content on success.
353        """
354        self._http.request(f"/api/v1/thread_messages/{message}", method="DELETE")
355
356    def get(self, message: str) -> ThreadMessage:
357        """
358        Retrieve a message
359        Returns a single message by its globally unique message ID. The authenticated
360        viewer must be able to read the message and its thread.
361        The response includes the message's content, sender information, and any
362        attachments that were loaded at creation time. For admin-authenticated
363        requests, an additional `admin` field is returned containing raw metadata
364        and the associated trajectory data (LLM input/output messages) if one exists.
365        A trajectory belongs to the agent response it produced, so `admin.trajectory`
366        is only populated on the response message. On the triggering user message
367        the trajectory is omitted and `admin.response_message` links to the agent
368        response (where the trajectory is shown), when a response exists.
369        If the message is not found or is not visible to the caller, a 404 is
370        returned.
371
372        Args:
373            message: Globally unique message ID (`msg_...`).
374
375        Returns:
376            The requested message, including its content, sender, and attachments.
377        """
378        return self._http.request(f"/api/v1/thread_messages/{message}", response_type=ThreadMessage)
379
380    def replace(self, message: str, input: ThreadMessageReplaceInput) -> Message:
381        """
382        Update a thread message
383        Edits an existing thread message and returns the updated message object.
384        A regular user may only edit messages they authored. Service-to-service
385        callers with elevated (`all_powerful`) scope may edit any accessible message
386        without an ownership check. Returns `403 Forbidden` when the caller does not
387        own the message.
388
389        Args:
390            message: ID of the message to update (`msg_...`).
391            input: Request body.
392            input.acl: Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged.
393            input.content: Replacement text content for the message. Omit to leave the content unchanged.
394            input.metadata: Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped.
395            input.type: Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected.
396            input.visibility: Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422.
397
398        Returns:
399            The updated message object.
400        """
401        return self._http.request(
402            f"/api/v1/thread_messages/{message}",
403            method="PUT",
404            body=input,
405            response_type=Message,
406        )
407
408    def replies(
409        self,
410        message: str,
411        *,
412        before_cursor: str | None = None,
413        after_cursor: str | None = None,
414        limit: int | None = None,
415        tree: bool | None = None,
416    ) -> PaginatedReplies:
417        """
418        List replies to a thread message
419        Returns a cursor-paginated list of reply messages for the specified thread
420        message. By default only direct (first-level) replies are returned. Set
421        `tree` to `true` to retrieve the full nested reply tree in a flat list,
422        ordered by creation time ascending.
423        The authenticated user must have access to the thread that contains the
424        message. If the message belongs to a team-scoped thread, the viewer is
425        automatically scoped to that team before the query executes.
426        Use `before_cursor` and `after_cursor` together with `limit` to page
427        through large reply threads. The `has_more` field in the response
428        indicates whether additional pages exist.
429
430        Args:
431            message: ID of the thread message to fetch replies for (`msg_...`).
432            before_cursor: Opaque pagination cursor. Returns replies created before this point. Obtain from `before_cursor` in a previous response.
433            after_cursor: Opaque pagination cursor. Returns replies created after this point. Obtain from `after_cursor` in a previous response.
434            limit: Maximum number of replies to return per page. Defaults to 20.
435            tree: When `true`, returns all replies in the nested reply tree (flattened). When `false` or omitted, returns only direct replies to the message.
436
437        Returns:
438            Cursor-paginated list of reply messages for the requested thread message.
439        """
440        query: dict[str, object] = {}
441        if before_cursor is not None:
442            query["before_cursor"] = before_cursor
443        if after_cursor is not None:
444            query["after_cursor"] = after_cursor
445        if limit is not None:
446            query["limit"] = limit
447        if tree is not None:
448            query["tree"] = tree
449        return self._http.request(
450            f"/api/v1/thread_messages/{message}/replies",
451            query=query,
452            response_type=PaginatedReplies,
453        )
class ReactionCreateInput(typing.TypedDict):
18class ReactionCreateInput(TypedDict):
19    "Add a reaction to a thread message"
20
21    emoji: str
22    'Emoji character or shortcode to add as a reaction, e.g. `" "` or `":thumbsup:"`.'

Add a reaction to a thread message

emoji: str

Emoji character or shortcode to add as a reaction, e.g. " " or ":thumbsup:".

class ThreadMessageReplaceInputAclAddItem(typing.TypedDict):
25class ThreadMessageReplaceInputAclAddItem(TypedDict, total=False):
26    actions: Required[list[str]]
27    'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.'
28    principal: str | None
29    'The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`.'
30    principal_type: Required[str]
31    'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
actions: Required[list[str]]

Array of action strings the principal is permitted to perform, e.g. ["read", "write"]. Must contain at least one entry.

principal: str | None

The identifier of the principal. A string ID for "user", "team", "org", and "agent" types; one of "admin", "member", or "viewer" for "org_role"; omit entirely when principal_type is "everyone".

principal_type: Required[str]

The kind of principal receiving the grant. One of "user", "team", "org", "org_role", "agent", or "everyone".

class ThreadMessageReplaceInputAclGrantsItem(typing.TypedDict):
34class ThreadMessageReplaceInputAclGrantsItem(TypedDict, total=False):
35    actions: Required[list[str]]
36    'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.'
37    principal: str | None
38    'The identifier of the principal. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`; omit entirely when `principal_type` is `"everyone"`.'
39    principal_type: Required[str]
40    'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
actions: Required[list[str]]

Array of action strings the principal is permitted to perform, e.g. ["read", "write"]. Must contain at least one entry.

principal: str | None

The identifier of the principal. A string ID for "user", "team", "org", and "agent" types; one of "admin", "member", or "viewer" for "org_role"; omit entirely when principal_type is "everyone".

principal_type: Required[str]

The kind of principal receiving the grant. One of "user", "team", "org", "org_role", "agent", or "everyone".

class ThreadMessageReplaceInputAclRemoveItem(typing.TypedDict):
43class ThreadMessageReplaceInputAclRemoveItem(TypedDict, total=False):
44    principal: str | None
45    'The identifier of the principal to remove. A string ID for `"user"`, `"team"`, `"org"`, and `"agent"` types; one of `"admin"`, `"member"`, or `"viewer"` for `"org_role"`. Omit when `principal_type` is `"everyone"`.'
46    principal_type: Required[str]
47    'The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
principal: str | None

The identifier of the principal to remove. A string ID for "user", "team", "org", and "agent" types; one of "admin", "member", or "viewer" for "org_role". Omit when principal_type is "everyone".

principal_type: Required[str]

The kind of principal to remove. One of "user", "team", "org", "org_role", "agent", or "everyone".

class ThreadMessageReplaceInputAcl(typing.TypedDict):
50class ThreadMessageReplaceInputAcl(TypedDict, total=False):
51    add: list[ThreadMessageReplaceInputAclAddItem] | None
52    "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`."
53    grants: list[ThreadMessageReplaceInputAclGrantsItem] | None
54    "Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array (`[]`) to clear all grants. Cannot be combined with `add` or `remove`."
55    remove: list[ThreadMessageReplaceInputAclRemoveItem] | None
56    "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`."

Patch mode: grants to add or merge into the existing list. Cannot be combined with grants.

Replace mode: the complete new list of grants that replaces all existing entries. Send an empty array ([]) to clear all grants. Cannot be combined with add or remove.

Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with grants.

class ThreadMessageReplaceInput(typing.TypedDict):
59class ThreadMessageReplaceInput(TypedDict, total=False):
60    "Update a thread message"
61
62    acl: ThreadMessageReplaceInputAcl | None
63    "Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged."
64    content: str | None
65    "Replacement text content for the message. Omit to leave the content unchanged."
66    metadata: dict[str, Any] | None
67    "Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped."
68    type: str | None
69    "Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected."
70    visibility: Literal["default", "private"] | None
71    "Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422."

Update a thread message

Access control list for a private message (replace or patch grants). Only valid when the message is already private. Omit to leave unchanged.

content: str | None

Replacement text content for the message. Omit to leave the content unchanged.

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

Replacement key-value metadata. Keys beginning with sys: are reserved and stripped.

type: str | None

Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as system are rejected.

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

Create-time message visibility. Supplying the existing value is harmless, but changing between default and private returns 422.

class ReactionCreateResponseData(pydantic.main.BaseModel):
74class ReactionCreateResponseData(BaseModel):
75    created_at: datetime | None = Field(
76        default=None, description="When the reaction was added (ISO 8601)."
77    )
78    feedback_type: str | None = Field(
79        default=None,
80        description='Category of feedback. Currently `"emoji_reaction"` for emoji responses.',
81    )
82    id: str = Field(..., description="Reaction ID (`umf_...`).")
83    message: str | None = Field(
84        default=None, description="ID of the message this reaction is attached to (`msg_...`)."
85    )
86    payload: dict[str, Any] | None = Field(
87        default=None,
88        description='Structured data for the reaction. For `"emoji_reaction"` types, includes an `emoji` key with the Unicode emoji string.',
89    )
90    updated_at: datetime | None = Field(
91        default=None, description="When the reaction was last modified (ISO 8601)."
92    )
93    user: str | None = Field(
94        default=None, description="ID of the user who added the reaction (`usr_...`)."
95    )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __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.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
created_at: datetime.datetime | None = None

When the reaction was added (ISO 8601).

feedback_type: str | None = None

Category of feedback. Currently "emoji_reaction" for emoji responses.

id: str = PydanticUndefined

Reaction ID (umf_...).

message: str | None = None

ID of the message this reaction is attached to (msg_...).

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

Structured data for the reaction. For "emoji_reaction" types, includes an emoji key with the Unicode emoji string.

updated_at: datetime.datetime | None = None

When the reaction was last modified (ISO 8601).

user: str | None = None

ID of the user who added the reaction (usr_...).

class ReactionCreateResponse(pydantic.main.BaseModel):
 98class ReactionCreateResponse(BaseModel):
 99    """
100    Successful response
101    """
102
103    data: ReactionCreateResponseData = Field(..., description="Reaction object that was created.")

Successful response

data: ReactionCreateResponseData = PydanticUndefined

Reaction object that was created.

class AsyncReactionResource:
106class AsyncReactionResource:
107    def __init__(self, http: HttpClient):
108        self._http = http
109
110    async def remove(self, message: str) -> None:
111        """
112        Remove a reaction from a thread message
113        Removes the authenticated user's emoji reaction from the specified thread
114        message. The reaction is identified by the combination of the message ID and
115        the emoji; only the reaction belonging to the calling user is removed.
116        Returns 204 No Content on success. Returns 404 if no matching reaction
117        exists for the user and emoji on that message, or if the message itself
118        cannot be found. The authenticated user must have read access to the thread
119        containing the message.
120
121        Args:
122            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
123
124        Returns:
125            Empty response body. HTTP 204 No Content on success.
126        """
127        await self._http.request(f"/api/v1/thread_messages/{message}/reactions", method="DELETE")
128
129    async def create(self, message: str, input: ReactionCreateInput) -> ReactionCreateResponse:
130        """
131        Add a reaction to a thread message
132        Adds an emoji reaction to the specified thread message on behalf of the
133        authenticated user. If the user has already reacted to the message with the
134        same emoji, the request returns a 409 Conflict rather than creating a
135        duplicate.
136        The authenticated user must have read access to the thread containing the
137        message. If the thread belongs to a team, the user must be a member of
138        that team.
139
140        Args:
141            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
142            input: Request body.
143            input.emoji: Emoji character or shortcode to add as a reaction, e.g. `" "` or `":thumbsup:"`.
144
145        Returns:
146            Successful response
147        """
148        return await self._http.request(
149            f"/api/v1/thread_messages/{message}/reactions",
150            method="POST",
151            body=input,
152            response_type=ReactionCreateResponse,
153        )
AsyncReactionResource(http: archastro.platform.runtime.http_client.HttpClient)
107    def __init__(self, http: HttpClient):
108        self._http = http
async def remove(self, message: str) -> None:
110    async def remove(self, message: str) -> None:
111        """
112        Remove a reaction from a thread message
113        Removes the authenticated user's emoji reaction from the specified thread
114        message. The reaction is identified by the combination of the message ID and
115        the emoji; only the reaction belonging to the calling user is removed.
116        Returns 204 No Content on success. Returns 404 if no matching reaction
117        exists for the user and emoji on that message, or if the message itself
118        cannot be found. The authenticated user must have read access to the thread
119        containing the message.
120
121        Args:
122            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
123
124        Returns:
125            Empty response body. HTTP 204 No Content on success.
126        """
127        await self._http.request(f"/api/v1/thread_messages/{message}/reactions", method="DELETE")

Remove a reaction from a thread message Removes the authenticated user's emoji reaction from the specified thread message. The reaction is identified by the combination of the message ID and the emoji; only the reaction belonging to the calling user is removed. Returns 204 No Content on success. Returns 404 if no matching reaction exists for the user and emoji on that message, or if the message itself cannot be found. The authenticated user must have read access to the thread containing the message.

Arguments:
  • message: Message ID (msg_...) of the thread message whose reaction should be removed.
Returns:

Empty response body. HTTP 204 No Content on success.

async def create( self, message: str, input: ReactionCreateInput) -> ReactionCreateResponse:
129    async def create(self, message: str, input: ReactionCreateInput) -> ReactionCreateResponse:
130        """
131        Add a reaction to a thread message
132        Adds an emoji reaction to the specified thread message on behalf of the
133        authenticated user. If the user has already reacted to the message with the
134        same emoji, the request returns a 409 Conflict rather than creating a
135        duplicate.
136        The authenticated user must have read access to the thread containing the
137        message. If the thread belongs to a team, the user must be a member of
138        that team.
139
140        Args:
141            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
142            input: Request body.
143            input.emoji: Emoji character or shortcode to add as a reaction, e.g. `" "` or `":thumbsup:"`.
144
145        Returns:
146            Successful response
147        """
148        return await self._http.request(
149            f"/api/v1/thread_messages/{message}/reactions",
150            method="POST",
151            body=input,
152            response_type=ReactionCreateResponse,
153        )

Add a reaction to a thread message Adds an emoji reaction to the specified thread message on behalf of the authenticated user. If the user has already reacted to the message with the same emoji, the request returns a 409 Conflict rather than creating a duplicate. The authenticated user must have read access to the thread containing the message. If the thread belongs to a team, the user must be a member of that team.

Arguments:
  • message: Message ID (msg_...) of the thread message whose reaction should be removed.
  • input: Request body.
  • input.emoji: Emoji character or shortcode to add as a reaction, e.g. " " or ":thumbsup:".
Returns:

Successful response

class AsyncThreadMessageResource:
156class AsyncThreadMessageResource:
157    def __init__(self, http: HttpClient):
158        self._http = http
159        self.reactions = AsyncReactionResource(http)
160
161    async def delete(self, message: str) -> None:
162        """
163        Delete a thread message
164        Permanently removes the specified message from its thread. This action
165        cannot be undone.
166        A message may be deleted by its author, an admin of the org the message
167        belongs to, an admin of the team that owns the thread, or the agent that
168        sent it. Service-to-service callers with elevated (`all_powerful`) scope
169        may delete any message in a thread they can access. Returns
170        `403 Forbidden` when the caller is not permitted to delete the message.
171
172        Args:
173            message: ID of the message to delete (`msg_...`).
174
175        Returns:
176            Empty body. The server responds with HTTP 204 No Content on success.
177        """
178        await self._http.request(f"/api/v1/thread_messages/{message}", method="DELETE")
179
180    async def get(self, message: str) -> ThreadMessage:
181        """
182        Retrieve a message
183        Returns a single message by its globally unique message ID. The authenticated
184        viewer must be able to read the message and its thread.
185        The response includes the message's content, sender information, and any
186        attachments that were loaded at creation time. For admin-authenticated
187        requests, an additional `admin` field is returned containing raw metadata
188        and the associated trajectory data (LLM input/output messages) if one exists.
189        A trajectory belongs to the agent response it produced, so `admin.trajectory`
190        is only populated on the response message. On the triggering user message
191        the trajectory is omitted and `admin.response_message` links to the agent
192        response (where the trajectory is shown), when a response exists.
193        If the message is not found or is not visible to the caller, a 404 is
194        returned.
195
196        Args:
197            message: Globally unique message ID (`msg_...`).
198
199        Returns:
200            The requested message, including its content, sender, and attachments.
201        """
202        return await self._http.request(
203            f"/api/v1/thread_messages/{message}",
204            response_type=ThreadMessage,
205        )
206
207    async def replace(self, message: str, input: ThreadMessageReplaceInput) -> Message:
208        """
209        Update a thread message
210        Edits an existing thread message and returns the updated message object.
211        A regular user may only edit messages they authored. Service-to-service
212        callers with elevated (`all_powerful`) scope may edit any accessible message
213        without an ownership check. Returns `403 Forbidden` when the caller does not
214        own the message.
215
216        Args:
217            message: ID of the message to update (`msg_...`).
218            input: Request body.
219            input.acl: Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged.
220            input.content: Replacement text content for the message. Omit to leave the content unchanged.
221            input.metadata: Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped.
222            input.type: Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected.
223            input.visibility: Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422.
224
225        Returns:
226            The updated message object.
227        """
228        return await self._http.request(
229            f"/api/v1/thread_messages/{message}",
230            method="PUT",
231            body=input,
232            response_type=Message,
233        )
234
235    async def replies(
236        self,
237        message: str,
238        *,
239        before_cursor: str | None = None,
240        after_cursor: str | None = None,
241        limit: int | None = None,
242        tree: bool | None = None,
243    ) -> PaginatedReplies:
244        """
245        List replies to a thread message
246        Returns a cursor-paginated list of reply messages for the specified thread
247        message. By default only direct (first-level) replies are returned. Set
248        `tree` to `true` to retrieve the full nested reply tree in a flat list,
249        ordered by creation time ascending.
250        The authenticated user must have access to the thread that contains the
251        message. If the message belongs to a team-scoped thread, the viewer is
252        automatically scoped to that team before the query executes.
253        Use `before_cursor` and `after_cursor` together with `limit` to page
254        through large reply threads. The `has_more` field in the response
255        indicates whether additional pages exist.
256
257        Args:
258            message: ID of the thread message to fetch replies for (`msg_...`).
259            before_cursor: Opaque pagination cursor. Returns replies created before this point. Obtain from `before_cursor` in a previous response.
260            after_cursor: Opaque pagination cursor. Returns replies created after this point. Obtain from `after_cursor` in a previous response.
261            limit: Maximum number of replies to return per page. Defaults to 20.
262            tree: When `true`, returns all replies in the nested reply tree (flattened). When `false` or omitted, returns only direct replies to the message.
263
264        Returns:
265            Cursor-paginated list of reply messages for the requested thread message.
266        """
267        query: dict[str, object] = {}
268        if before_cursor is not None:
269            query["before_cursor"] = before_cursor
270        if after_cursor is not None:
271            query["after_cursor"] = after_cursor
272        if limit is not None:
273            query["limit"] = limit
274        if tree is not None:
275            query["tree"] = tree
276        return await self._http.request(
277            f"/api/v1/thread_messages/{message}/replies",
278            query=query,
279            response_type=PaginatedReplies,
280        )
AsyncThreadMessageResource(http: archastro.platform.runtime.http_client.HttpClient)
157    def __init__(self, http: HttpClient):
158        self._http = http
159        self.reactions = AsyncReactionResource(http)
reactions
async def delete(self, message: str) -> None:
161    async def delete(self, message: str) -> None:
162        """
163        Delete a thread message
164        Permanently removes the specified message from its thread. This action
165        cannot be undone.
166        A message may be deleted by its author, an admin of the org the message
167        belongs to, an admin of the team that owns the thread, or the agent that
168        sent it. Service-to-service callers with elevated (`all_powerful`) scope
169        may delete any message in a thread they can access. Returns
170        `403 Forbidden` when the caller is not permitted to delete the message.
171
172        Args:
173            message: ID of the message to delete (`msg_...`).
174
175        Returns:
176            Empty body. The server responds with HTTP 204 No Content on success.
177        """
178        await self._http.request(f"/api/v1/thread_messages/{message}", method="DELETE")

Delete a thread message Permanently removes the specified message from its thread. This action cannot be undone. A message may be deleted by its author, an admin of the org the message belongs to, an admin of the team that owns the thread, or the agent that sent it. Service-to-service callers with elevated (all_powerful) scope may delete any message in a thread they can access. Returns 403 Forbidden when the caller is not permitted to delete the message.

Arguments:
  • message: ID of the message to delete (msg_...).
Returns:

Empty body. The server responds with HTTP 204 No Content on success.

async def get(self, message: str) -> archastro.platform.types.threads.ThreadMessage:
180    async def get(self, message: str) -> ThreadMessage:
181        """
182        Retrieve a message
183        Returns a single message by its globally unique message ID. The authenticated
184        viewer must be able to read the message and its thread.
185        The response includes the message's content, sender information, and any
186        attachments that were loaded at creation time. For admin-authenticated
187        requests, an additional `admin` field is returned containing raw metadata
188        and the associated trajectory data (LLM input/output messages) if one exists.
189        A trajectory belongs to the agent response it produced, so `admin.trajectory`
190        is only populated on the response message. On the triggering user message
191        the trajectory is omitted and `admin.response_message` links to the agent
192        response (where the trajectory is shown), when a response exists.
193        If the message is not found or is not visible to the caller, a 404 is
194        returned.
195
196        Args:
197            message: Globally unique message ID (`msg_...`).
198
199        Returns:
200            The requested message, including its content, sender, and attachments.
201        """
202        return await self._http.request(
203            f"/api/v1/thread_messages/{message}",
204            response_type=ThreadMessage,
205        )

Retrieve a message Returns a single message by its globally unique message ID. The authenticated viewer must be able to read the message and its thread. The response includes the message's content, sender information, and any attachments that were loaded at creation time. For admin-authenticated requests, an additional admin field is returned containing raw metadata and the associated trajectory data (LLM input/output messages) if one exists. A trajectory belongs to the agent response it produced, so admin.trajectory is only populated on the response message. On the triggering user message the trajectory is omitted and admin.response_message links to the agent response (where the trajectory is shown), when a response exists. If the message is not found or is not visible to the caller, a 404 is returned.

Arguments:
  • message: Globally unique message ID (msg_...).
Returns:

The requested message, including its content, sender, and attachments.

async def replace( self, message: str, input: ThreadMessageReplaceInput) -> archastro.platform.types.common.Message:
207    async def replace(self, message: str, input: ThreadMessageReplaceInput) -> Message:
208        """
209        Update a thread message
210        Edits an existing thread message and returns the updated message object.
211        A regular user may only edit messages they authored. Service-to-service
212        callers with elevated (`all_powerful`) scope may edit any accessible message
213        without an ownership check. Returns `403 Forbidden` when the caller does not
214        own the message.
215
216        Args:
217            message: ID of the message to update (`msg_...`).
218            input: Request body.
219            input.acl: Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged.
220            input.content: Replacement text content for the message. Omit to leave the content unchanged.
221            input.metadata: Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped.
222            input.type: Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected.
223            input.visibility: Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422.
224
225        Returns:
226            The updated message object.
227        """
228        return await self._http.request(
229            f"/api/v1/thread_messages/{message}",
230            method="PUT",
231            body=input,
232            response_type=Message,
233        )

Update a thread message Edits an existing thread message and returns the updated message object. A regular user may only edit messages they authored. Service-to-service callers with elevated (all_powerful) scope may edit any accessible message without an ownership check. Returns 403 Forbidden when the caller does not own the message.

Arguments:
  • message: ID of the message to update (msg_...).
  • input: Request body.
  • input.acl: Access control list for a private message (replace or patch grants). Only valid when the message is already private. Omit to leave unchanged.
  • input.content: Replacement text content for the message. Omit to leave the content unchanged.
  • input.metadata: Replacement key-value metadata. Keys beginning with sys: are reserved and stripped.
  • input.type: Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as system are rejected.
  • input.visibility: Create-time message visibility. Supplying the existing value is harmless, but changing between default and private returns 422.
Returns:

The updated message object.

async def replies( self, message: str, *, before_cursor: str | None = None, after_cursor: str | None = None, limit: int | None = None, tree: bool | None = None) -> archastro.platform.types.common.PaginatedReplies:
235    async def replies(
236        self,
237        message: str,
238        *,
239        before_cursor: str | None = None,
240        after_cursor: str | None = None,
241        limit: int | None = None,
242        tree: bool | None = None,
243    ) -> PaginatedReplies:
244        """
245        List replies to a thread message
246        Returns a cursor-paginated list of reply messages for the specified thread
247        message. By default only direct (first-level) replies are returned. Set
248        `tree` to `true` to retrieve the full nested reply tree in a flat list,
249        ordered by creation time ascending.
250        The authenticated user must have access to the thread that contains the
251        message. If the message belongs to a team-scoped thread, the viewer is
252        automatically scoped to that team before the query executes.
253        Use `before_cursor` and `after_cursor` together with `limit` to page
254        through large reply threads. The `has_more` field in the response
255        indicates whether additional pages exist.
256
257        Args:
258            message: ID of the thread message to fetch replies for (`msg_...`).
259            before_cursor: Opaque pagination cursor. Returns replies created before this point. Obtain from `before_cursor` in a previous response.
260            after_cursor: Opaque pagination cursor. Returns replies created after this point. Obtain from `after_cursor` in a previous response.
261            limit: Maximum number of replies to return per page. Defaults to 20.
262            tree: When `true`, returns all replies in the nested reply tree (flattened). When `false` or omitted, returns only direct replies to the message.
263
264        Returns:
265            Cursor-paginated list of reply messages for the requested thread message.
266        """
267        query: dict[str, object] = {}
268        if before_cursor is not None:
269            query["before_cursor"] = before_cursor
270        if after_cursor is not None:
271            query["after_cursor"] = after_cursor
272        if limit is not None:
273            query["limit"] = limit
274        if tree is not None:
275            query["tree"] = tree
276        return await self._http.request(
277            f"/api/v1/thread_messages/{message}/replies",
278            query=query,
279            response_type=PaginatedReplies,
280        )

List replies to a thread message Returns a cursor-paginated list of reply messages for the specified thread message. By default only direct (first-level) replies are returned. Set tree to true to retrieve the full nested reply tree in a flat list, ordered by creation time ascending. The authenticated user must have access to the thread that contains the message. If the message belongs to a team-scoped thread, the viewer is automatically scoped to that team before the query executes. Use before_cursor and after_cursor together with limit to page through large reply threads. The has_more field in the response indicates whether additional pages exist.

Arguments:
  • message: ID of the thread message to fetch replies for (msg_...).
  • before_cursor: Opaque pagination cursor. Returns replies created before this point. Obtain from before_cursor in a previous response.
  • after_cursor: Opaque pagination cursor. Returns replies created after this point. Obtain from after_cursor in a previous response.
  • limit: Maximum number of replies to return per page. Defaults to 20.
  • tree: When true, returns all replies in the nested reply tree (flattened). When false or omitted, returns only direct replies to the message.
Returns:

Cursor-paginated list of reply messages for the requested thread message.

class ReactionResource:
283class ReactionResource:
284    def __init__(self, http: SyncHttpClient):
285        self._http = http
286
287    def remove(self, message: str) -> None:
288        """
289        Remove a reaction from a thread message
290        Removes the authenticated user's emoji reaction from the specified thread
291        message. The reaction is identified by the combination of the message ID and
292        the emoji; only the reaction belonging to the calling user is removed.
293        Returns 204 No Content on success. Returns 404 if no matching reaction
294        exists for the user and emoji on that message, or if the message itself
295        cannot be found. The authenticated user must have read access to the thread
296        containing the message.
297
298        Args:
299            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
300
301        Returns:
302            Empty response body. HTTP 204 No Content on success.
303        """
304        self._http.request(f"/api/v1/thread_messages/{message}/reactions", method="DELETE")
305
306    def create(self, message: str, input: ReactionCreateInput) -> ReactionCreateResponse:
307        """
308        Add a reaction to a thread message
309        Adds an emoji reaction to the specified thread message on behalf of the
310        authenticated user. If the user has already reacted to the message with the
311        same emoji, the request returns a 409 Conflict rather than creating a
312        duplicate.
313        The authenticated user must have read access to the thread containing the
314        message. If the thread belongs to a team, the user must be a member of
315        that team.
316
317        Args:
318            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
319            input: Request body.
320            input.emoji: Emoji character or shortcode to add as a reaction, e.g. `" "` or `":thumbsup:"`.
321
322        Returns:
323            Successful response
324        """
325        return self._http.request(
326            f"/api/v1/thread_messages/{message}/reactions",
327            method="POST",
328            body=input,
329            response_type=ReactionCreateResponse,
330        )
ReactionResource(http: archastro.platform.runtime.http_client.SyncHttpClient)
284    def __init__(self, http: SyncHttpClient):
285        self._http = http
def remove(self, message: str) -> None:
287    def remove(self, message: str) -> None:
288        """
289        Remove a reaction from a thread message
290        Removes the authenticated user's emoji reaction from the specified thread
291        message. The reaction is identified by the combination of the message ID and
292        the emoji; only the reaction belonging to the calling user is removed.
293        Returns 204 No Content on success. Returns 404 if no matching reaction
294        exists for the user and emoji on that message, or if the message itself
295        cannot be found. The authenticated user must have read access to the thread
296        containing the message.
297
298        Args:
299            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
300
301        Returns:
302            Empty response body. HTTP 204 No Content on success.
303        """
304        self._http.request(f"/api/v1/thread_messages/{message}/reactions", method="DELETE")

Remove a reaction from a thread message Removes the authenticated user's emoji reaction from the specified thread message. The reaction is identified by the combination of the message ID and the emoji; only the reaction belonging to the calling user is removed. Returns 204 No Content on success. Returns 404 if no matching reaction exists for the user and emoji on that message, or if the message itself cannot be found. The authenticated user must have read access to the thread containing the message.

Arguments:
  • message: Message ID (msg_...) of the thread message whose reaction should be removed.
Returns:

Empty response body. HTTP 204 No Content on success.

def create( self, message: str, input: ReactionCreateInput) -> ReactionCreateResponse:
306    def create(self, message: str, input: ReactionCreateInput) -> ReactionCreateResponse:
307        """
308        Add a reaction to a thread message
309        Adds an emoji reaction to the specified thread message on behalf of the
310        authenticated user. If the user has already reacted to the message with the
311        same emoji, the request returns a 409 Conflict rather than creating a
312        duplicate.
313        The authenticated user must have read access to the thread containing the
314        message. If the thread belongs to a team, the user must be a member of
315        that team.
316
317        Args:
318            message: Message ID (`msg_...`) of the thread message whose reaction should be removed.
319            input: Request body.
320            input.emoji: Emoji character or shortcode to add as a reaction, e.g. `" "` or `":thumbsup:"`.
321
322        Returns:
323            Successful response
324        """
325        return self._http.request(
326            f"/api/v1/thread_messages/{message}/reactions",
327            method="POST",
328            body=input,
329            response_type=ReactionCreateResponse,
330        )

Add a reaction to a thread message Adds an emoji reaction to the specified thread message on behalf of the authenticated user. If the user has already reacted to the message with the same emoji, the request returns a 409 Conflict rather than creating a duplicate. The authenticated user must have read access to the thread containing the message. If the thread belongs to a team, the user must be a member of that team.

Arguments:
  • message: Message ID (msg_...) of the thread message whose reaction should be removed.
  • input: Request body.
  • input.emoji: Emoji character or shortcode to add as a reaction, e.g. " " or ":thumbsup:".
Returns:

Successful response

class ThreadMessageResource:
333class ThreadMessageResource:
334    def __init__(self, http: SyncHttpClient):
335        self._http = http
336        self.reactions = ReactionResource(http)
337
338    def delete(self, message: str) -> None:
339        """
340        Delete a thread message
341        Permanently removes the specified message from its thread. This action
342        cannot be undone.
343        A message may be deleted by its author, an admin of the org the message
344        belongs to, an admin of the team that owns the thread, or the agent that
345        sent it. Service-to-service callers with elevated (`all_powerful`) scope
346        may delete any message in a thread they can access. Returns
347        `403 Forbidden` when the caller is not permitted to delete the message.
348
349        Args:
350            message: ID of the message to delete (`msg_...`).
351
352        Returns:
353            Empty body. The server responds with HTTP 204 No Content on success.
354        """
355        self._http.request(f"/api/v1/thread_messages/{message}", method="DELETE")
356
357    def get(self, message: str) -> ThreadMessage:
358        """
359        Retrieve a message
360        Returns a single message by its globally unique message ID. The authenticated
361        viewer must be able to read the message and its thread.
362        The response includes the message's content, sender information, and any
363        attachments that were loaded at creation time. For admin-authenticated
364        requests, an additional `admin` field is returned containing raw metadata
365        and the associated trajectory data (LLM input/output messages) if one exists.
366        A trajectory belongs to the agent response it produced, so `admin.trajectory`
367        is only populated on the response message. On the triggering user message
368        the trajectory is omitted and `admin.response_message` links to the agent
369        response (where the trajectory is shown), when a response exists.
370        If the message is not found or is not visible to the caller, a 404 is
371        returned.
372
373        Args:
374            message: Globally unique message ID (`msg_...`).
375
376        Returns:
377            The requested message, including its content, sender, and attachments.
378        """
379        return self._http.request(f"/api/v1/thread_messages/{message}", response_type=ThreadMessage)
380
381    def replace(self, message: str, input: ThreadMessageReplaceInput) -> Message:
382        """
383        Update a thread message
384        Edits an existing thread message and returns the updated message object.
385        A regular user may only edit messages they authored. Service-to-service
386        callers with elevated (`all_powerful`) scope may edit any accessible message
387        without an ownership check. Returns `403 Forbidden` when the caller does not
388        own the message.
389
390        Args:
391            message: ID of the message to update (`msg_...`).
392            input: Request body.
393            input.acl: Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged.
394            input.content: Replacement text content for the message. Omit to leave the content unchanged.
395            input.metadata: Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped.
396            input.type: Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected.
397            input.visibility: Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422.
398
399        Returns:
400            The updated message object.
401        """
402        return self._http.request(
403            f"/api/v1/thread_messages/{message}",
404            method="PUT",
405            body=input,
406            response_type=Message,
407        )
408
409    def replies(
410        self,
411        message: str,
412        *,
413        before_cursor: str | None = None,
414        after_cursor: str | None = None,
415        limit: int | None = None,
416        tree: bool | None = None,
417    ) -> PaginatedReplies:
418        """
419        List replies to a thread message
420        Returns a cursor-paginated list of reply messages for the specified thread
421        message. By default only direct (first-level) replies are returned. Set
422        `tree` to `true` to retrieve the full nested reply tree in a flat list,
423        ordered by creation time ascending.
424        The authenticated user must have access to the thread that contains the
425        message. If the message belongs to a team-scoped thread, the viewer is
426        automatically scoped to that team before the query executes.
427        Use `before_cursor` and `after_cursor` together with `limit` to page
428        through large reply threads. The `has_more` field in the response
429        indicates whether additional pages exist.
430
431        Args:
432            message: ID of the thread message to fetch replies for (`msg_...`).
433            before_cursor: Opaque pagination cursor. Returns replies created before this point. Obtain from `before_cursor` in a previous response.
434            after_cursor: Opaque pagination cursor. Returns replies created after this point. Obtain from `after_cursor` in a previous response.
435            limit: Maximum number of replies to return per page. Defaults to 20.
436            tree: When `true`, returns all replies in the nested reply tree (flattened). When `false` or omitted, returns only direct replies to the message.
437
438        Returns:
439            Cursor-paginated list of reply messages for the requested thread message.
440        """
441        query: dict[str, object] = {}
442        if before_cursor is not None:
443            query["before_cursor"] = before_cursor
444        if after_cursor is not None:
445            query["after_cursor"] = after_cursor
446        if limit is not None:
447            query["limit"] = limit
448        if tree is not None:
449            query["tree"] = tree
450        return self._http.request(
451            f"/api/v1/thread_messages/{message}/replies",
452            query=query,
453            response_type=PaginatedReplies,
454        )
ThreadMessageResource(http: archastro.platform.runtime.http_client.SyncHttpClient)
334    def __init__(self, http: SyncHttpClient):
335        self._http = http
336        self.reactions = ReactionResource(http)
reactions
def delete(self, message: str) -> None:
338    def delete(self, message: str) -> None:
339        """
340        Delete a thread message
341        Permanently removes the specified message from its thread. This action
342        cannot be undone.
343        A message may be deleted by its author, an admin of the org the message
344        belongs to, an admin of the team that owns the thread, or the agent that
345        sent it. Service-to-service callers with elevated (`all_powerful`) scope
346        may delete any message in a thread they can access. Returns
347        `403 Forbidden` when the caller is not permitted to delete the message.
348
349        Args:
350            message: ID of the message to delete (`msg_...`).
351
352        Returns:
353            Empty body. The server responds with HTTP 204 No Content on success.
354        """
355        self._http.request(f"/api/v1/thread_messages/{message}", method="DELETE")

Delete a thread message Permanently removes the specified message from its thread. This action cannot be undone. A message may be deleted by its author, an admin of the org the message belongs to, an admin of the team that owns the thread, or the agent that sent it. Service-to-service callers with elevated (all_powerful) scope may delete any message in a thread they can access. Returns 403 Forbidden when the caller is not permitted to delete the message.

Arguments:
  • message: ID of the message to delete (msg_...).
Returns:

Empty body. The server responds with HTTP 204 No Content on success.

def get(self, message: str) -> archastro.platform.types.threads.ThreadMessage:
357    def get(self, message: str) -> ThreadMessage:
358        """
359        Retrieve a message
360        Returns a single message by its globally unique message ID. The authenticated
361        viewer must be able to read the message and its thread.
362        The response includes the message's content, sender information, and any
363        attachments that were loaded at creation time. For admin-authenticated
364        requests, an additional `admin` field is returned containing raw metadata
365        and the associated trajectory data (LLM input/output messages) if one exists.
366        A trajectory belongs to the agent response it produced, so `admin.trajectory`
367        is only populated on the response message. On the triggering user message
368        the trajectory is omitted and `admin.response_message` links to the agent
369        response (where the trajectory is shown), when a response exists.
370        If the message is not found or is not visible to the caller, a 404 is
371        returned.
372
373        Args:
374            message: Globally unique message ID (`msg_...`).
375
376        Returns:
377            The requested message, including its content, sender, and attachments.
378        """
379        return self._http.request(f"/api/v1/thread_messages/{message}", response_type=ThreadMessage)

Retrieve a message Returns a single message by its globally unique message ID. The authenticated viewer must be able to read the message and its thread. The response includes the message's content, sender information, and any attachments that were loaded at creation time. For admin-authenticated requests, an additional admin field is returned containing raw metadata and the associated trajectory data (LLM input/output messages) if one exists. A trajectory belongs to the agent response it produced, so admin.trajectory is only populated on the response message. On the triggering user message the trajectory is omitted and admin.response_message links to the agent response (where the trajectory is shown), when a response exists. If the message is not found or is not visible to the caller, a 404 is returned.

Arguments:
  • message: Globally unique message ID (msg_...).
Returns:

The requested message, including its content, sender, and attachments.

def replace( self, message: str, input: ThreadMessageReplaceInput) -> archastro.platform.types.common.Message:
381    def replace(self, message: str, input: ThreadMessageReplaceInput) -> Message:
382        """
383        Update a thread message
384        Edits an existing thread message and returns the updated message object.
385        A regular user may only edit messages they authored. Service-to-service
386        callers with elevated (`all_powerful`) scope may edit any accessible message
387        without an ownership check. Returns `403 Forbidden` when the caller does not
388        own the message.
389
390        Args:
391            message: ID of the message to update (`msg_...`).
392            input: Request body.
393            input.acl: Access control list for a private message (replace or patch grants). Only valid when the message is already `private`. Omit to leave unchanged.
394            input.content: Replacement text content for the message. Omit to leave the content unchanged.
395            input.metadata: Replacement key-value metadata. Keys beginning with `sys:` are reserved and stripped.
396            input.type: Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as `system` are rejected.
397            input.visibility: Create-time message visibility. Supplying the existing value is harmless, but changing between `default` and `private` returns 422.
398
399        Returns:
400            The updated message object.
401        """
402        return self._http.request(
403            f"/api/v1/thread_messages/{message}",
404            method="PUT",
405            body=input,
406            response_type=Message,
407        )

Update a thread message Edits an existing thread message and returns the updated message object. A regular user may only edit messages they authored. Service-to-service callers with elevated (all_powerful) scope may edit any accessible message without an ownership check. Returns 403 Forbidden when the caller does not own the message.

Arguments:
  • message: ID of the message to update (msg_...).
  • input: Request body.
  • input.acl: Access control list for a private message (replace or patch grants). Only valid when the message is already private. Omit to leave unchanged.
  • input.content: Replacement text content for the message. Omit to leave the content unchanged.
  • input.metadata: Replacement key-value metadata. Keys beginning with sys: are reserved and stripped.
  • input.type: Replacement client-defined classification. Free-form string up to 64 characters; platform-reserved values such as system are rejected.
  • input.visibility: Create-time message visibility. Supplying the existing value is harmless, but changing between default and private returns 422.
Returns:

The updated message object.

def replies( self, message: str, *, before_cursor: str | None = None, after_cursor: str | None = None, limit: int | None = None, tree: bool | None = None) -> archastro.platform.types.common.PaginatedReplies:
409    def replies(
410        self,
411        message: str,
412        *,
413        before_cursor: str | None = None,
414        after_cursor: str | None = None,
415        limit: int | None = None,
416        tree: bool | None = None,
417    ) -> PaginatedReplies:
418        """
419        List replies to a thread message
420        Returns a cursor-paginated list of reply messages for the specified thread
421        message. By default only direct (first-level) replies are returned. Set
422        `tree` to `true` to retrieve the full nested reply tree in a flat list,
423        ordered by creation time ascending.
424        The authenticated user must have access to the thread that contains the
425        message. If the message belongs to a team-scoped thread, the viewer is
426        automatically scoped to that team before the query executes.
427        Use `before_cursor` and `after_cursor` together with `limit` to page
428        through large reply threads. The `has_more` field in the response
429        indicates whether additional pages exist.
430
431        Args:
432            message: ID of the thread message to fetch replies for (`msg_...`).
433            before_cursor: Opaque pagination cursor. Returns replies created before this point. Obtain from `before_cursor` in a previous response.
434            after_cursor: Opaque pagination cursor. Returns replies created after this point. Obtain from `after_cursor` in a previous response.
435            limit: Maximum number of replies to return per page. Defaults to 20.
436            tree: When `true`, returns all replies in the nested reply tree (flattened). When `false` or omitted, returns only direct replies to the message.
437
438        Returns:
439            Cursor-paginated list of reply messages for the requested thread message.
440        """
441        query: dict[str, object] = {}
442        if before_cursor is not None:
443            query["before_cursor"] = before_cursor
444        if after_cursor is not None:
445            query["after_cursor"] = after_cursor
446        if limit is not None:
447            query["limit"] = limit
448        if tree is not None:
449            query["tree"] = tree
450        return self._http.request(
451            f"/api/v1/thread_messages/{message}/replies",
452            query=query,
453            response_type=PaginatedReplies,
454        )

List replies to a thread message Returns a cursor-paginated list of reply messages for the specified thread message. By default only direct (first-level) replies are returned. Set tree to true to retrieve the full nested reply tree in a flat list, ordered by creation time ascending. The authenticated user must have access to the thread that contains the message. If the message belongs to a team-scoped thread, the viewer is automatically scoped to that team before the query executes. Use before_cursor and after_cursor together with limit to page through large reply threads. The has_more field in the response indicates whether additional pages exist.

Arguments:
  • message: ID of the thread message to fetch replies for (msg_...).
  • before_cursor: Opaque pagination cursor. Returns replies created before this point. Obtain from before_cursor in a previous response.
  • after_cursor: Opaque pagination cursor. Returns replies created after this point. Obtain from after_cursor in a previous response.
  • limit: Maximum number of replies to return per page. Defaults to 20.
  • tree: When true, returns all replies in the nested reply tree (flattened). When false or omitted, returns only direct replies to the message.
Returns:

Cursor-paginated list of reply messages for the requested thread message.