archastro.platform.channels.api_chat_channel
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: 068983a8456f 4 5from collections.abc import Callable 6from datetime import datetime 7from typing import TYPE_CHECKING, Any, Literal, Required, TypedDict 8 9if TYPE_CHECKING: 10 from archastro.phx_channel.socket import Socket 11 12 13class ApiChatForkThreadInput(TypedDict, total=False): 14 "Fork a sub-thread from an existing message" 15 16 message_id: Required[str] 17 title: str 18 19 20class ApiChatMarkThreadReadInput(TypedDict): 21 "Mark a thread as read up to a given message" 22 23 message_id: str 24 25 26class ApiChatLoadMoreMessagesInput(TypedDict, total=False): 27 "Load additional messages with cursor-based pagination" 28 29 after_cursor: str 30 before_cursor: str 31 include_metadata: bool 32 limit: int 33 34 35class ApiChatPostMessageInput(TypedDict, total=False): 36 "Post a new message with optional uploads and reply-to" 37 38 content: Required[str] 39 idempotency_key: str 40 reply_to: str 41 uploads: list[dict[str, Any]] 42 43 44class ApiChatPostSimpleMessageInput(TypedDict, total=False): 45 "Post a simple text message" 46 47 content: str 48 idempotency_key: str 49 reply_to: str 50 51 52class ApiChatEditMessageInput(TypedDict): 53 "Edit an existing message's content" 54 55 content: str 56 message_id: str 57 58 59class ApiChatDeleteMessageInput(TypedDict): 60 "Delete a message" 61 62 message_id: str 63 64 65class ApiChatAddReactionInput(TypedDict): 66 "Add an emoji reaction to a message" 67 68 emoji: str 69 message_id: str 70 71 72class ApiChatRemoveReactionInput(TypedDict): 73 "Remove an emoji reaction from a message" 74 75 emoji: str 76 message_id: str 77 78 79class ApiChatTypingInput(TypedDict): 80 "Signal that the current user has started or stopped typing in the thread" 81 82 is_typing: bool 83 84 85class MessageAddedPayloadMessageAclAddItem(TypedDict, total=False): 86 actions: Required[list[str]] 87 'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.' 88 principal: str | None 89 '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"`.' 90 principal_type: Required[str] 91 'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.' 92 93 94class MessageAddedPayloadMessageAclGrantsItem(TypedDict, total=False): 95 actions: Required[list[str]] 96 'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.' 97 principal: str | None 98 '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"`.' 99 principal_type: Required[str] 100 'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.' 101 102 103class MessageAddedPayloadMessageAclRemoveItem(TypedDict, total=False): 104 principal: str | None 105 '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"`.' 106 principal_type: Required[str] 107 'The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.' 108 109 110class MessageAddedPayloadMessageAcl(TypedDict, total=False): 111 add: list[MessageAddedPayloadMessageAclAddItem] | None 112 "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`." 113 grants: list[MessageAddedPayloadMessageAclGrantsItem] | None 114 "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`." 115 remove: list[MessageAddedPayloadMessageAclRemoveItem] | None 116 "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`." 117 118 119class MessageAddedPayloadMessageActorsItemProfilePicture(TypedDict, total=False): 120 file: str | None 121 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 122 height: int | None 123 "Height of the image in pixels. `null` if not known." 124 media: str | None 125 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 126 mime_type: str | None 127 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 128 refresh_url: str | None 129 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 130 url: str | None 131 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 132 width: int | None 133 "Width of the image in pixels. `null` if not known." 134 135 136class MessageAddedPayloadMessageActorsItem(TypedDict, total=False): 137 alias: str | None 138 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 139 id: str | None 140 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 141 name: str | None 142 "Display name of the actor shown in the UI. `null` if no name is set." 143 profile_picture: MessageAddedPayloadMessageActorsItemProfilePicture | None 144 "Profile picture for the actor. `null` if the actor has no profile picture." 145 146 147class MessageAddedPayloadMessageAttachmentsItemImageSource(TypedDict, total=False): 148 file: str | None 149 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 150 height: int | None 151 "Height of the image in pixels. `null` if not known." 152 media: str | None 153 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 154 mime_type: str | None 155 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 156 refresh_url: str | None 157 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 158 url: str | None 159 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 160 width: int | None 161 "Width of the image in pixels. `null` if not known." 162 163 164class MessageAddedPayloadMessageAttachmentsItemVariantsItemImageSource(TypedDict, total=False): 165 file: str | None 166 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 167 height: int | None 168 "Height of the image in pixels. `null` if not known." 169 media: str | None 170 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 171 mime_type: str | None 172 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 173 refresh_url: str | None 174 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 175 url: str | None 176 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 177 width: int | None 178 "Width of the image in pixels. `null` if not known." 179 180 181class MessageAddedPayloadMessageAttachmentsItemVariantsItem(TypedDict, total=False): 182 content_type: str | None 183 'MIME type of this variant\'s file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded.' 184 created_at: datetime | None 185 "When this variant was created (ISO 8601)." 186 file: str | None 187 "ID of the underlying storage file that backs this variant (`fil_...`)." 188 filename: str | None 189 "Original filename of the uploaded file for this variant. `null` if the file is not loaded." 190 height: int | None 191 "Height of this variant in pixels. `null` if not recorded." 192 id: Required[str] 193 "Media variant ID (`mvr_...`)." 194 image_source: MessageAddedPayloadMessageAttachmentsItemVariantsItemImageSource | None 195 "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types." 196 updated_at: datetime | None 197 "When this variant was last updated (ISO 8601)." 198 url: str | None 199 "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable." 200 variant_key: str | None 201 'Identifier for this variant\'s processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview).' 202 width: int | None 203 "Width of this variant in pixels. `null` if not recorded." 204 205 206class MessageAddedPayloadMessageAttachmentsItem(TypedDict, total=False): 207 content_type: str | None 208 'MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.' 209 description: str | None 210 "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types." 211 filename: str | None 212 'Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.' 213 height: int | None 214 "Height in pixels of the media item. Present on `media` type only. `null` otherwise." 215 id: Required[str] 216 "Unique identifier for this attachment within the message." 217 image_height: int | None 218 "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise." 219 image_source: MessageAddedPayloadMessageAttachmentsItemImageSource | None 220 "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise." 221 image_url: str | None 222 "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise." 223 image_width: int | None 224 "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise." 225 media_type: str | None 226 'The media category, e.g. `"video"` or `"audio"`. Present on `media` type only; omitted otherwise.' 227 name: str | None 228 "Display name of the media item. Present on `media` type only. `null` otherwise." 229 object: dict[str, Any] | None 230 "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. Omitted on other types." 231 title: str | None 232 "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types." 233 type: Required[str] 234 'The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present.' 235 url: str | None 236 "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types." 237 variants: list[MessageAddedPayloadMessageAttachmentsItemVariantsItem] | None 238 "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only; omitted otherwise." 239 version: int | None 240 "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise." 241 width: int | None 242 "Width in pixels of the media item. Present on `media` type only. `null` otherwise." 243 244 245class MessageAddedPayloadMessageReactionsItem(TypedDict, total=False): 246 payload: dict[str, Any] | None 247 'Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `" "`).' 248 type: Required[str] 249 'Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions.' 250 user: str | None 251 "Public ID of the user who added the reaction (`usr_...`)." 252 253 254class MessageAddedPayloadMessage(TypedDict, total=False): 255 acl: MessageAddedPayloadMessageAcl | None 256 "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else." 257 actors: list[MessageAddedPayloadMessageActorsItem] | None 258 "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry." 259 agent: str | None 260 "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users." 261 agent_mode: Literal["cli", "embedded"] | None 262 "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." 263 attachments: list[MessageAddedPayloadMessageAttachmentsItem] | None 264 "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments." 265 branched_thread: str | None 266 "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread." 267 content: str | None 268 "Text content of the message. `null` for messages that contain only attachments." 269 created_at: str | None 270 "When the message was posted (ISO 8601)." 271 has_replies: bool | None 272 "Whether this message has at least one reply. Only present when explicitly requested or computed by the server." 273 id: Required[str] 274 "Message ID (`msg_...`)." 275 idempotency_key: str | None 276 "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one." 277 is_deleted: bool | None 278 "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages." 279 legacy_agent: str | None 280 "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users." 281 metadata: dict[str, Any] | None 282 "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set." 283 org: str | None 284 "ID of the organization that owns this message (`org_...`)." 285 reactions: list[MessageAddedPayloadMessageReactionsItem] | None 286 "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded." 287 rendering_mode: str | None 288 'Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies.' 289 replies: list[dict[str, Any]] | None 290 "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message." 291 replies_after_cursor: str | None 292 "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response." 293 replies_before_cursor: str | None 294 "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response." 295 reply_count: int | None 296 "Total number of direct replies to this message. Only present when explicitly requested or computed by the server." 297 reply_to: dict[str, Any] | None 298 "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded." 299 root_message_id: str | None 300 "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." 301 sandbox: str | None 302 "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages." 303 team: str | None 304 "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped." 305 thread: str | None 306 "ID of the thread this message belongs to (`thr_...`)." 307 type: str | None 308 "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." 309 user: str | dict[str, Any] | None 310 "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents." 311 visibility: Literal["default", "private"] | None 312 "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees." 313 314 315class MessageAddedPayload(TypedDict, total=False): 316 "Broadcast when a new message is added to a thread" 317 318 after_cursor: str | None 319 before_cursor: str | None 320 message: MessageAddedPayloadMessage | None 321 "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata." 322 thread_id: str | None 323 324 325class MessageUpdatedPayloadMessageAclAddItem(TypedDict, total=False): 326 actions: Required[list[str]] 327 'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.' 328 principal: str | None 329 '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"`.' 330 principal_type: Required[str] 331 'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.' 332 333 334class MessageUpdatedPayloadMessageAclGrantsItem(TypedDict, total=False): 335 actions: Required[list[str]] 336 'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.' 337 principal: str | None 338 '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"`.' 339 principal_type: Required[str] 340 'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.' 341 342 343class MessageUpdatedPayloadMessageAclRemoveItem(TypedDict, total=False): 344 principal: str | None 345 '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"`.' 346 principal_type: Required[str] 347 'The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.' 348 349 350class MessageUpdatedPayloadMessageAcl(TypedDict, total=False): 351 add: list[MessageUpdatedPayloadMessageAclAddItem] | None 352 "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`." 353 grants: list[MessageUpdatedPayloadMessageAclGrantsItem] | None 354 "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`." 355 remove: list[MessageUpdatedPayloadMessageAclRemoveItem] | None 356 "Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with `grants`." 357 358 359class MessageUpdatedPayloadMessageActorsItemProfilePicture(TypedDict, total=False): 360 file: str | None 361 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 362 height: int | None 363 "Height of the image in pixels. `null` if not known." 364 media: str | None 365 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 366 mime_type: str | None 367 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 368 refresh_url: str | None 369 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 370 url: str | None 371 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 372 width: int | None 373 "Width of the image in pixels. `null` if not known." 374 375 376class MessageUpdatedPayloadMessageActorsItem(TypedDict, total=False): 377 alias: str | None 378 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 379 id: str | None 380 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 381 name: str | None 382 "Display name of the actor shown in the UI. `null` if no name is set." 383 profile_picture: MessageUpdatedPayloadMessageActorsItemProfilePicture | None 384 "Profile picture for the actor. `null` if the actor has no profile picture." 385 386 387class MessageUpdatedPayloadMessageAttachmentsItemImageSource(TypedDict, total=False): 388 file: str | None 389 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 390 height: int | None 391 "Height of the image in pixels. `null` if not known." 392 media: str | None 393 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 394 mime_type: str | None 395 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 396 refresh_url: str | None 397 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 398 url: str | None 399 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 400 width: int | None 401 "Width of the image in pixels. `null` if not known." 402 403 404class MessageUpdatedPayloadMessageAttachmentsItemVariantsItemImageSource(TypedDict, total=False): 405 file: str | None 406 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 407 height: int | None 408 "Height of the image in pixels. `null` if not known." 409 media: str | None 410 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 411 mime_type: str | None 412 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 413 refresh_url: str | None 414 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 415 url: str | None 416 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 417 width: int | None 418 "Width of the image in pixels. `null` if not known." 419 420 421class MessageUpdatedPayloadMessageAttachmentsItemVariantsItem(TypedDict, total=False): 422 content_type: str | None 423 'MIME type of this variant\'s file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded.' 424 created_at: datetime | None 425 "When this variant was created (ISO 8601)." 426 file: str | None 427 "ID of the underlying storage file that backs this variant (`fil_...`)." 428 filename: str | None 429 "Original filename of the uploaded file for this variant. `null` if the file is not loaded." 430 height: int | None 431 "Height of this variant in pixels. `null` if not recorded." 432 id: Required[str] 433 "Media variant ID (`mvr_...`)." 434 image_source: MessageUpdatedPayloadMessageAttachmentsItemVariantsItemImageSource | None 435 "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types." 436 updated_at: datetime | None 437 "When this variant was last updated (ISO 8601)." 438 url: str | None 439 "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable." 440 variant_key: str | None 441 'Identifier for this variant\'s processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview).' 442 width: int | None 443 "Width of this variant in pixels. `null` if not recorded." 444 445 446class MessageUpdatedPayloadMessageAttachmentsItem(TypedDict, total=False): 447 content_type: str | None 448 'MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.' 449 description: str | None 450 "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types." 451 filename: str | None 452 'Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.' 453 height: int | None 454 "Height in pixels of the media item. Present on `media` type only. `null` otherwise." 455 id: Required[str] 456 "Unique identifier for this attachment within the message." 457 image_height: int | None 458 "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise." 459 image_source: MessageUpdatedPayloadMessageAttachmentsItemImageSource | None 460 "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise." 461 image_url: str | None 462 "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise." 463 image_width: int | None 464 "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise." 465 media_type: str | None 466 'The media category, e.g. `"video"` or `"audio"`. Present on `media` type only; omitted otherwise.' 467 name: str | None 468 "Display name of the media item. Present on `media` type only. `null` otherwise." 469 object: dict[str, Any] | None 470 "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. Omitted on other types." 471 title: str | None 472 "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types." 473 type: Required[str] 474 'The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present.' 475 url: str | None 476 "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types." 477 variants: list[MessageUpdatedPayloadMessageAttachmentsItemVariantsItem] | None 478 "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only; omitted otherwise." 479 version: int | None 480 "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise." 481 width: int | None 482 "Width in pixels of the media item. Present on `media` type only. `null` otherwise." 483 484 485class MessageUpdatedPayloadMessageReactionsItem(TypedDict, total=False): 486 payload: dict[str, Any] | None 487 'Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `" "`).' 488 type: Required[str] 489 'Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions.' 490 user: str | None 491 "Public ID of the user who added the reaction (`usr_...`)." 492 493 494class MessageUpdatedPayloadMessage(TypedDict, total=False): 495 acl: MessageUpdatedPayloadMessageAcl | None 496 "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else." 497 actors: list[MessageUpdatedPayloadMessageActorsItem] | None 498 "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry." 499 agent: str | None 500 "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users." 501 agent_mode: Literal["cli", "embedded"] | None 502 "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." 503 attachments: list[MessageUpdatedPayloadMessageAttachmentsItem] | None 504 "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments." 505 branched_thread: str | None 506 "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread." 507 content: str | None 508 "Text content of the message. `null` for messages that contain only attachments." 509 created_at: str | None 510 "When the message was posted (ISO 8601)." 511 has_replies: bool | None 512 "Whether this message has at least one reply. Only present when explicitly requested or computed by the server." 513 id: Required[str] 514 "Message ID (`msg_...`)." 515 idempotency_key: str | None 516 "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one." 517 is_deleted: bool | None 518 "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages." 519 legacy_agent: str | None 520 "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users." 521 metadata: dict[str, Any] | None 522 "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set." 523 org: str | None 524 "ID of the organization that owns this message (`org_...`)." 525 reactions: list[MessageUpdatedPayloadMessageReactionsItem] | None 526 "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded." 527 rendering_mode: str | None 528 'Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies.' 529 replies: list[dict[str, Any]] | None 530 "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message." 531 replies_after_cursor: str | None 532 "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response." 533 replies_before_cursor: str | None 534 "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response." 535 reply_count: int | None 536 "Total number of direct replies to this message. Only present when explicitly requested or computed by the server." 537 reply_to: dict[str, Any] | None 538 "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded." 539 root_message_id: str | None 540 "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." 541 sandbox: str | None 542 "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages." 543 team: str | None 544 "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped." 545 thread: str | None 546 "ID of the thread this message belongs to (`thr_...`)." 547 type: str | None 548 "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." 549 user: str | dict[str, Any] | None 550 "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents." 551 visibility: Literal["default", "private"] | None 552 "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees." 553 554 555class MessageUpdatedPayload(TypedDict, total=False): 556 "Broadcast when a message is updated or removed" 557 558 message: MessageUpdatedPayloadMessage | None 559 "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata." 560 thread_id: str | None 561 562 563class ThreadEventPayload(TypedDict, total=False): 564 "Broadcast thread-level events (agent updates, read state, unread counts)" 565 566 payload: dict[str, Any] | None 567 thread_id: str | None 568 type: str | None 569 570 571class SystemEventPayload(TypedDict, total=False): 572 "Broadcast system-wide events" 573 574 event: dict[str, Any] | None 575 576 577class TypingPayloadActorProfilePicture(TypedDict, total=False): 578 file: str | None 579 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 580 height: int | None 581 "Height of the image in pixels. `null` if not known." 582 media: str | None 583 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 584 mime_type: str | None 585 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 586 refresh_url: str | None 587 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 588 url: str | None 589 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 590 width: int | None 591 "Width of the image in pixels. `null` if not known." 592 593 594class TypingPayloadActor(TypedDict, total=False): 595 alias: str | None 596 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 597 id: str | None 598 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 599 name: str | None 600 "Display name of the actor shown in the UI. `null` if no name is set." 601 profile_picture: TypingPayloadActorProfilePicture | None 602 "Profile picture for the actor. `null` if the actor has no profile picture." 603 604 605class TypingPayload(TypedDict, total=False): 606 "Broadcast when a participant (human or agent) starts or stops typing. Ephemeral; never persisted." 607 608 actor: TypingPayloadActor | None 609 "The entity that authored a message, either a human user or an agent." 610 is_typing: bool | None 611 thread_id: str | None 612 613 614# Channel for real-time chat messaging. 615# Supports team-scoped and user-scoped threads with keyed, transient, and direct 616# thread access patterns. 617class ApiChatChannel: 618 def __init__(self, channel, join_response=None): 619 self._channel = channel 620 self.join_response = join_response 621 622 # Join a team-scoped thread by ID 623 @staticmethod 624 def topic_team_thread(team_id: str, thread_id: str) -> str: 625 return f"api:chat:team:{team_id}:thread:{thread_id}" 626 627 # Join a team-scoped thread by ID 628 @classmethod 629 async def join_team_thread( 630 cls, 631 socket: "Socket", 632 team_id: str, 633 thread_id: str, 634 *, 635 after_cursor: str | None = None, 636 before_cursor: str | None = None, 637 include_metadata: bool | None = None, 638 limit: int | None = None, 639 ) -> "ApiChatChannel": 640 topic = cls.topic_team_thread(team_id, thread_id) 641 channel = socket.channel(topic) 642 payload: dict[str, object] = {} 643 if after_cursor is not None: 644 payload["after_cursor"] = after_cursor 645 if before_cursor is not None: 646 payload["before_cursor"] = before_cursor 647 if include_metadata is not None: 648 payload["include_metadata"] = include_metadata 649 if limit is not None: 650 payload["limit"] = limit 651 join_response = await channel.join(payload) 652 return cls(channel, join_response) 653 654 # Join or create a team-scoped keyed thread 655 @staticmethod 656 def topic_team_keyed(team_id: str, key: str) -> str: 657 return f"api:chat:team:{team_id}:key:{key}" 658 659 # Join or create a team-scoped keyed thread 660 @classmethod 661 async def join_team_keyed( 662 cls, 663 socket: "Socket", 664 team_id: str, 665 key: str, 666 *, 667 after_cursor: str | None = None, 668 before_cursor: str | None = None, 669 include_metadata: bool | None = None, 670 limit: int | None = None, 671 ) -> "ApiChatChannel": 672 topic = cls.topic_team_keyed(team_id, key) 673 channel = socket.channel(topic) 674 payload: dict[str, object] = {} 675 if after_cursor is not None: 676 payload["after_cursor"] = after_cursor 677 if before_cursor is not None: 678 payload["before_cursor"] = before_cursor 679 if include_metadata is not None: 680 payload["include_metadata"] = include_metadata 681 if limit is not None: 682 payload["limit"] = limit 683 join_response = await channel.join(payload) 684 return cls(channel, join_response) 685 686 # Join a team-scoped transient (ephemeral) thread 687 @staticmethod 688 def topic_team_transient(team_id: str, key: str) -> str: 689 return f"api:chat:team:{team_id}:transient:{key}" 690 691 # Join a team-scoped transient (ephemeral) thread 692 @classmethod 693 async def join_team_transient( 694 cls, 695 socket: "Socket", 696 team_id: str, 697 key: str, 698 *, 699 after_cursor: str | None = None, 700 before_cursor: str | None = None, 701 include_metadata: bool | None = None, 702 limit: int | None = None, 703 ) -> "ApiChatChannel": 704 topic = cls.topic_team_transient(team_id, key) 705 channel = socket.channel(topic) 706 payload: dict[str, object] = {} 707 if after_cursor is not None: 708 payload["after_cursor"] = after_cursor 709 if before_cursor is not None: 710 payload["before_cursor"] = before_cursor 711 if include_metadata is not None: 712 payload["include_metadata"] = include_metadata 713 if limit is not None: 714 payload["limit"] = limit 715 join_response = await channel.join(payload) 716 return cls(channel, join_response) 717 718 # Join a user-scoped thread by ID, optionally supplying local tools for a personal thread 719 @staticmethod 720 def topic_user_thread(thread_id: str) -> str: 721 return f"api:chat:user:thread:{thread_id}" 722 723 # Join a user-scoped thread by ID, optionally supplying local tools for a personal thread 724 @classmethod 725 async def join_user_thread( 726 cls, 727 socket: "Socket", 728 thread_id: str, 729 *, 730 after_cursor: str | None = None, 731 before_cursor: str | None = None, 732 include_metadata: bool | None = None, 733 limit: int | None = None, 734 local_tool_provider_id: str | None = None, 735 local_tools: list[dict[str, Any]] | None = None, 736 ) -> "ApiChatChannel": 737 topic = cls.topic_user_thread(thread_id) 738 channel = socket.channel(topic) 739 payload: dict[str, object] = {} 740 if after_cursor is not None: 741 payload["after_cursor"] = after_cursor 742 if before_cursor is not None: 743 payload["before_cursor"] = before_cursor 744 if include_metadata is not None: 745 payload["include_metadata"] = include_metadata 746 if limit is not None: 747 payload["limit"] = limit 748 if local_tool_provider_id is not None: 749 payload["local_tool_provider_id"] = local_tool_provider_id 750 if local_tools is not None: 751 payload["local_tools"] = local_tools 752 join_response = await channel.join(payload) 753 return cls(channel, join_response) 754 755 # Join or create a user-scoped keyed thread 756 @staticmethod 757 def topic_user_keyed(key: str) -> str: 758 return f"api:chat:user:key:{key}" 759 760 # Join or create a user-scoped keyed thread 761 @classmethod 762 async def join_user_keyed( 763 cls, 764 socket: "Socket", 765 key: str, 766 *, 767 after_cursor: str | None = None, 768 before_cursor: str | None = None, 769 include_metadata: bool | None = None, 770 limit: int | None = None, 771 ) -> "ApiChatChannel": 772 topic = cls.topic_user_keyed(key) 773 channel = socket.channel(topic) 774 payload: dict[str, object] = {} 775 if after_cursor is not None: 776 payload["after_cursor"] = after_cursor 777 if before_cursor is not None: 778 payload["before_cursor"] = before_cursor 779 if include_metadata is not None: 780 payload["include_metadata"] = include_metadata 781 if limit is not None: 782 payload["limit"] = limit 783 join_response = await channel.join(payload) 784 return cls(channel, join_response) 785 786 # Join a user-scoped transient (ephemeral) thread 787 @staticmethod 788 def topic_user_transient(key: str) -> str: 789 return f"api:chat:user:transient:{key}" 790 791 # Join a user-scoped transient (ephemeral) thread 792 @classmethod 793 async def join_user_transient( 794 cls, 795 socket: "Socket", 796 key: str, 797 *, 798 after_cursor: str | None = None, 799 before_cursor: str | None = None, 800 include_metadata: bool | None = None, 801 limit: int | None = None, 802 ) -> "ApiChatChannel": 803 topic = cls.topic_user_transient(key) 804 channel = socket.channel(topic) 805 payload: dict[str, object] = {} 806 if after_cursor is not None: 807 payload["after_cursor"] = after_cursor 808 if before_cursor is not None: 809 payload["before_cursor"] = before_cursor 810 if include_metadata is not None: 811 payload["include_metadata"] = include_metadata 812 if limit is not None: 813 payload["limit"] = limit 814 join_response = await channel.join(payload) 815 return cls(channel, join_response) 816 817 # Leave the underlying channel. 818 async def leave(self): 819 await self._channel.leave() 820 821 # Fork a sub-thread from an existing message 822 async def api_chat_fork_thread(self, payload: ApiChatForkThreadInput) -> dict[str, Any]: 823 return await self._channel.push("api:chat:fork_thread", payload) 824 825 # Mark a thread as read up to a given message 826 async def api_chat_mark_thread_read( 827 self, payload: ApiChatMarkThreadReadInput 828 ) -> dict[str, Any]: 829 return await self._channel.push("api:chat:mark_thread_read", payload) 830 831 # List all messages in the current thread 832 async def api_chat_list_messages(self, payload: dict) -> dict[str, Any]: 833 return await self._channel.push("api:chat:list_messages", payload) 834 835 # Load additional messages with cursor-based pagination 836 async def api_chat_load_more_messages( 837 self, payload: ApiChatLoadMoreMessagesInput 838 ) -> dict[str, Any]: 839 return await self._channel.push("api:chat:load_more_messages", payload) 840 841 # Post a new message with optional uploads and reply-to 842 async def api_chat_post_message(self, payload: ApiChatPostMessageInput) -> dict[str, Any]: 843 return await self._channel.push("api:chat:post_message", payload) 844 845 # Post a simple text message 846 async def api_chat_post_simple_message( 847 self, payload: ApiChatPostSimpleMessageInput 848 ) -> dict[str, Any]: 849 return await self._channel.push("api:chat:post_simple_message", payload) 850 851 # Edit an existing message's content 852 async def api_chat_edit_message(self, payload: ApiChatEditMessageInput) -> dict[str, Any]: 853 return await self._channel.push("api:chat:edit_message", payload) 854 855 # Delete a message 856 async def api_chat_delete_message(self, payload: ApiChatDeleteMessageInput) -> dict[str, Any]: 857 return await self._channel.push("api:chat:delete_message", payload) 858 859 # Add an emoji reaction to a message 860 async def api_chat_add_reaction(self, payload: ApiChatAddReactionInput) -> dict[str, Any]: 861 return await self._channel.push("api:chat:add_reaction", payload) 862 863 # Remove an emoji reaction from a message 864 async def api_chat_remove_reaction(self, payload: ApiChatRemoveReactionInput) -> dict[str, Any]: 865 return await self._channel.push("api:chat:remove_reaction", payload) 866 867 # Signal that the current user has started or stopped typing in the thread 868 async def api_chat_typing(self, payload: ApiChatTypingInput) -> dict[str, Any]: 869 return await self._channel.push("api:chat:typing", payload) 870 871 # Broadcast when a new message is added to a thread 872 def on_message_added( 873 self, callback: Callable[[MessageAddedPayload], None] 874 ) -> Callable[[], None]: 875 return self._channel.on("message_added", callback) 876 877 # Broadcast when a message is updated or removed 878 def on_message_updated( 879 self, callback: Callable[[MessageUpdatedPayload], None] 880 ) -> Callable[[], None]: 881 return self._channel.on("message_updated", callback) 882 883 # Broadcast thread-level events (agent updates, read state, unread counts) 884 def on_thread_event(self, callback: Callable[[ThreadEventPayload], None]) -> Callable[[], None]: 885 return self._channel.on("thread_event", callback) 886 887 # Broadcast system-wide events 888 def on_system_event(self, callback: Callable[[SystemEventPayload], None]) -> Callable[[], None]: 889 return self._channel.on("system_event", callback) 890 891 # Broadcast when a participant (human or agent) starts or stops typing. Ephemeral; never persisted. 892 def on_typing(self, callback: Callable[[TypingPayload], None]) -> Callable[[], None]: 893 return self._channel.on("typing", callback)
14class ApiChatForkThreadInput(TypedDict, total=False): 15 "Fork a sub-thread from an existing message" 16 17 message_id: Required[str] 18 title: str
Fork a sub-thread from an existing message
21class ApiChatMarkThreadReadInput(TypedDict): 22 "Mark a thread as read up to a given message" 23 24 message_id: str
Mark a thread as read up to a given message
27class ApiChatLoadMoreMessagesInput(TypedDict, total=False): 28 "Load additional messages with cursor-based pagination" 29 30 after_cursor: str 31 before_cursor: str 32 include_metadata: bool 33 limit: int
Load additional messages with cursor-based pagination
36class ApiChatPostMessageInput(TypedDict, total=False): 37 "Post a new message with optional uploads and reply-to" 38 39 content: Required[str] 40 idempotency_key: str 41 reply_to: str 42 uploads: list[dict[str, Any]]
Post a new message with optional uploads and reply-to
45class ApiChatPostSimpleMessageInput(TypedDict, total=False): 46 "Post a simple text message" 47 48 content: str 49 idempotency_key: str 50 reply_to: str
Post a simple text message
53class ApiChatEditMessageInput(TypedDict): 54 "Edit an existing message's content" 55 56 content: str 57 message_id: str
Edit an existing message's content
Delete a message
66class ApiChatAddReactionInput(TypedDict): 67 "Add an emoji reaction to a message" 68 69 emoji: str 70 message_id: str
Add an emoji reaction to a message
73class ApiChatRemoveReactionInput(TypedDict): 74 "Remove an emoji reaction from a message" 75 76 emoji: str 77 message_id: str
Remove an emoji reaction from a message
80class ApiChatTypingInput(TypedDict): 81 "Signal that the current user has started or stopped typing in the thread" 82 83 is_typing: bool
Signal that the current user has started or stopped typing in the thread
86class MessageAddedPayloadMessageAclAddItem(TypedDict, total=False): 87 actions: Required[list[str]] 88 'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.' 89 principal: str | None 90 '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"`.' 91 principal_type: Required[str] 92 'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
Array of action strings the principal is permitted to perform, e.g. ["read", "write"]. Must contain at least one entry.
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".
95class MessageAddedPayloadMessageAclGrantsItem(TypedDict, total=False): 96 actions: Required[list[str]] 97 'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.' 98 principal: str | None 99 '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"`.' 100 principal_type: Required[str] 101 'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
Array of action strings the principal is permitted to perform, e.g. ["read", "write"]. Must contain at least one entry.
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".
104class MessageAddedPayloadMessageAclRemoveItem(TypedDict, total=False): 105 principal: str | None 106 '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"`.' 107 principal_type: Required[str] 108 'The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
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".
111class MessageAddedPayloadMessageAcl(TypedDict, total=False): 112 add: list[MessageAddedPayloadMessageAclAddItem] | None 113 "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`." 114 grants: list[MessageAddedPayloadMessageAclGrantsItem] | None 115 "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`." 116 remove: list[MessageAddedPayloadMessageAclRemoveItem] | None 117 "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.
Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with grants.
120class MessageAddedPayloadMessageActorsItemProfilePicture(TypedDict, total=False): 121 file: str | None 122 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 123 height: int | None 124 "Height of the image in pixels. `null` if not known." 125 media: str | None 126 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 127 mime_type: str | None 128 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 129 refresh_url: str | None 130 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 131 url: str | None 132 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 133 width: int | None 134 "Width of the image in pixels. `null` if not known."
ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.
ID of the associated media record (med_...). null when the image is not linked to a media entity.
Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.
Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.
137class MessageAddedPayloadMessageActorsItem(TypedDict, total=False): 138 alias: str | None 139 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 140 id: str | None 141 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 142 name: str | None 143 "Display name of the actor shown in the UI. `null` if no name is set." 144 profile_picture: MessageAddedPayloadMessageActorsItemProfilePicture | None 145 "Profile picture for the actor. `null` if the actor has no profile picture."
Short handle or alias for the actor, used as an alternate display identifier. null if not configured.
Composite actor identifier. Format is "user-<usr_...>" for human users or "agent-<agi_...>" for agents.
Profile picture for the actor. null if the actor has no profile picture.
148class MessageAddedPayloadMessageAttachmentsItemImageSource(TypedDict, total=False): 149 file: str | None 150 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 151 height: int | None 152 "Height of the image in pixels. `null` if not known." 153 media: str | None 154 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 155 mime_type: str | None 156 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 157 refresh_url: str | None 158 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 159 url: str | None 160 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 161 width: int | None 162 "Width of the image in pixels. `null` if not known."
ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.
ID of the associated media record (med_...). null when the image is not linked to a media entity.
Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.
Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.
165class MessageAddedPayloadMessageAttachmentsItemVariantsItemImageSource(TypedDict, total=False): 166 file: str | None 167 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 168 height: int | None 169 "Height of the image in pixels. `null` if not known." 170 media: str | None 171 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 172 mime_type: str | None 173 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 174 refresh_url: str | None 175 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 176 url: str | None 177 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 178 width: int | None 179 "Width of the image in pixels. `null` if not known."
ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.
ID of the associated media record (med_...). null when the image is not linked to a media entity.
Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.
Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.
182class MessageAddedPayloadMessageAttachmentsItemVariantsItem(TypedDict, total=False): 183 content_type: str | None 184 'MIME type of this variant\'s file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded.' 185 created_at: datetime | None 186 "When this variant was created (ISO 8601)." 187 file: str | None 188 "ID of the underlying storage file that backs this variant (`fil_...`)." 189 filename: str | None 190 "Original filename of the uploaded file for this variant. `null` if the file is not loaded." 191 height: int | None 192 "Height of this variant in pixels. `null` if not recorded." 193 id: Required[str] 194 "Media variant ID (`mvr_...`)." 195 image_source: MessageAddedPayloadMessageAttachmentsItemVariantsItemImageSource | None 196 "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types." 197 updated_at: datetime | None 198 "When this variant was last updated (ISO 8601)." 199 url: str | None 200 "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable." 201 variant_key: str | None 202 'Identifier for this variant\'s processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview).' 203 width: int | None 204 "Width of this variant in pixels. `null` if not recorded."
MIME type of this variant's file (e.g., "image/jpeg", "video/mp4"). null if the file is not loaded.
Original filename of the uploaded file for this variant. null if the file is not loaded.
Resolved image delivery metadata for this variant, including dimensions and CDN URL. null for non-image content types.
Signed download URL for this variant, resolved at request time. null if the file is unavailable.
207class MessageAddedPayloadMessageAttachmentsItem(TypedDict, total=False): 208 content_type: str | None 209 'MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.' 210 description: str | None 211 "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types." 212 filename: str | None 213 'Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.' 214 height: int | None 215 "Height in pixels of the media item. Present on `media` type only. `null` otherwise." 216 id: Required[str] 217 "Unique identifier for this attachment within the message." 218 image_height: int | None 219 "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise." 220 image_source: MessageAddedPayloadMessageAttachmentsItemImageSource | None 221 "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise." 222 image_url: str | None 223 "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise." 224 image_width: int | None 225 "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise." 226 media_type: str | None 227 'The media category, e.g. `"video"` or `"audio"`. Present on `media` type only; omitted otherwise.' 228 name: str | None 229 "Display name of the media item. Present on `media` type only. `null` otherwise." 230 object: dict[str, Any] | None 231 "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. Omitted on other types." 232 title: str | None 233 "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types." 234 type: Required[str] 235 'The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present.' 236 url: str | None 237 "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types." 238 variants: list[MessageAddedPayloadMessageAttachmentsItemVariantsItem] | None 239 "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only; omitted otherwise." 240 version: int | None 241 "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise." 242 width: int | None 243 "Width in pixels of the media item. Present on `media` type only. `null` otherwise."
MIME type of the attached file, e.g. "image/png" or "application/pdf". Present on file, artifact, and media types. null otherwise.
Short description. The page meta-description for scraped_link, the artifact description for artifact, and the task description for task types. null on other types.
Original filename of the attached file, e.g. "report.pdf". Present on file, artifact, and media types. null otherwise.
Height in pixels of the scraped preview image. Present on scraped_link type only. null otherwise.
Image source metadata for inline rendering. Present on file, scraped_link, artifact, and media types when the content is an image. null otherwise.
URL of the preview image extracted from the scraped page. Present on scraped_link type only. null otherwise.
Width in pixels of the scraped preview image. Present on scraped_link type only. null otherwise.
The media category, e.g. "video" or "audio". Present on media type only; omitted otherwise.
The full embedded object payload. For task type, contains the task record. For action type, contains the action definition. For chart type, contains the chart with its inline spec. Omitted on other types.
Display title. The page title for scraped_link, the artifact name for artifact, and the task title for task types. null on other types.
The attachment type. One of "file", "scraped_link", "artifact", "task", "media", "action", or "chart". Determines which additional fields are present.
URL to access the resource. A signed download URL for file and artifact types; the original URL for scraped_link; a media playback URL for media. null on task and action types.
Array of available encoding variants for the media item (e.g. different resolutions). Present on media type only; omitted otherwise.
246class MessageAddedPayloadMessageReactionsItem(TypedDict, total=False): 247 payload: dict[str, Any] | None 248 'Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `" "`).' 249 type: Required[str] 250 'Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions.' 251 user: str | None 252 "Public ID of the user who added the reaction (`usr_...`)."
Type-specific reaction data. For "emoji_reaction" reactions, contains an emoji key with the Unicode emoji string (e.g., " ").
255class MessageAddedPayloadMessage(TypedDict, total=False): 256 acl: MessageAddedPayloadMessageAcl | None 257 "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else." 258 actors: list[MessageAddedPayloadMessageActorsItem] | None 259 "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry." 260 agent: str | None 261 "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users." 262 agent_mode: Literal["cli", "embedded"] | None 263 "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." 264 attachments: list[MessageAddedPayloadMessageAttachmentsItem] | None 265 "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments." 266 branched_thread: str | None 267 "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread." 268 content: str | None 269 "Text content of the message. `null` for messages that contain only attachments." 270 created_at: str | None 271 "When the message was posted (ISO 8601)." 272 has_replies: bool | None 273 "Whether this message has at least one reply. Only present when explicitly requested or computed by the server." 274 id: Required[str] 275 "Message ID (`msg_...`)." 276 idempotency_key: str | None 277 "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one." 278 is_deleted: bool | None 279 "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages." 280 legacy_agent: str | None 281 "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users." 282 metadata: dict[str, Any] | None 283 "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set." 284 org: str | None 285 "ID of the organization that owns this message (`org_...`)." 286 reactions: list[MessageAddedPayloadMessageReactionsItem] | None 287 "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded." 288 rendering_mode: str | None 289 'Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies.' 290 replies: list[dict[str, Any]] | None 291 "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message." 292 replies_after_cursor: str | None 293 "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response." 294 replies_before_cursor: str | None 295 "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response." 296 reply_count: int | None 297 "Total number of direct replies to this message. Only present when explicitly requested or computed by the server." 298 reply_to: dict[str, Any] | None 299 "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded." 300 root_message_id: str | None 301 "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." 302 sandbox: str | None 303 "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages." 304 team: str | None 305 "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped." 306 thread: str | None 307 "ID of the thread this message belongs to (`thr_...`)." 308 type: str | None 309 "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." 310 user: str | dict[str, Any] | None 311 "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents." 312 visibility: Literal["default", "private"] | None 313 "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees."
Access control list for private messages (grants with read action). Only returned to resource owners (and privileged/org-admin viewers) via server-side field_redactions: [acl: :owner]; null for everyone else.
Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.
ID of the agent user that sent this message (agi_...). null for messages sent by human users.
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.
Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.
ID of the thread that was branched from this message (thr_...). null if this message has not spawned a branch thread.
Whether this message has at least one reply. Only present when explicitly requested or computed by the server.
Client-supplied idempotency key used to deduplicate message sends. null if the sender did not provide one.
Whether this message is a deletion tombstone. true only on the message_updated broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always false for live messages.
Identifier of the legacy chat agent that sent this message, if applicable. null for messages sent by users or modern agent users.
Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.
Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.
Display hint for how the message should be rendered. One of "reply", "direct", or "inline". null for user-authored messages, which are always rendered as standard replies.
Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.
Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.
Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.
Total number of direct replies to this message. Only present when explicitly requested or computed by the server.
The parent message this message is a reply to, expanded as a full message object when loaded. null if this is a top-level message or the association is not preloaded.
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.
ID of the developer sandbox this message belongs to (dsb_...). null for non-sandbox messages.
ID of the team this message is scoped to (tem_...). null if the message is not team-scoped.
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.
316class MessageAddedPayload(TypedDict, total=False): 317 "Broadcast when a new message is added to a thread" 318 319 after_cursor: str | None 320 before_cursor: str | None 321 message: MessageAddedPayloadMessage | None 322 "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata." 323 thread_id: str | None
Broadcast when a new message is added to a thread
A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.
326class MessageUpdatedPayloadMessageAclAddItem(TypedDict, total=False): 327 actions: Required[list[str]] 328 'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.' 329 principal: str | None 330 '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"`.' 331 principal_type: Required[str] 332 'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
Array of action strings the principal is permitted to perform, e.g. ["read", "write"]. Must contain at least one entry.
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".
335class MessageUpdatedPayloadMessageAclGrantsItem(TypedDict, total=False): 336 actions: Required[list[str]] 337 'Array of action strings the principal is permitted to perform, e.g. `["read", "write"]`. Must contain at least one entry.' 338 principal: str | None 339 '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"`.' 340 principal_type: Required[str] 341 'The kind of principal receiving the grant. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
Array of action strings the principal is permitted to perform, e.g. ["read", "write"]. Must contain at least one entry.
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".
344class MessageUpdatedPayloadMessageAclRemoveItem(TypedDict, total=False): 345 principal: str | None 346 '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"`.' 347 principal_type: Required[str] 348 'The kind of principal to remove. One of `"user"`, `"team"`, `"org"`, `"org_role"`, `"agent"`, or `"everyone"`.'
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".
351class MessageUpdatedPayloadMessageAcl(TypedDict, total=False): 352 add: list[MessageUpdatedPayloadMessageAclAddItem] | None 353 "Patch mode: grants to add or merge into the existing list. Cannot be combined with `grants`." 354 grants: list[MessageUpdatedPayloadMessageAclGrantsItem] | None 355 "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`." 356 remove: list[MessageUpdatedPayloadMessageAclRemoveItem] | None 357 "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.
Patch mode: principals whose grants should be removed from the existing list. Cannot be combined with grants.
360class MessageUpdatedPayloadMessageActorsItemProfilePicture(TypedDict, total=False): 361 file: str | None 362 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 363 height: int | None 364 "Height of the image in pixels. `null` if not known." 365 media: str | None 366 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 367 mime_type: str | None 368 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 369 refresh_url: str | None 370 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 371 url: str | None 372 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 373 width: int | None 374 "Width of the image in pixels. `null` if not known."
ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.
ID of the associated media record (med_...). null when the image is not linked to a media entity.
Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.
Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.
377class MessageUpdatedPayloadMessageActorsItem(TypedDict, total=False): 378 alias: str | None 379 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 380 id: str | None 381 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 382 name: str | None 383 "Display name of the actor shown in the UI. `null` if no name is set." 384 profile_picture: MessageUpdatedPayloadMessageActorsItemProfilePicture | None 385 "Profile picture for the actor. `null` if the actor has no profile picture."
Short handle or alias for the actor, used as an alternate display identifier. null if not configured.
Composite actor identifier. Format is "user-<usr_...>" for human users or "agent-<agi_...>" for agents.
Profile picture for the actor. null if the actor has no profile picture.
388class MessageUpdatedPayloadMessageAttachmentsItemImageSource(TypedDict, total=False): 389 file: str | None 390 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 391 height: int | None 392 "Height of the image in pixels. `null` if not known." 393 media: str | None 394 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 395 mime_type: str | None 396 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 397 refresh_url: str | None 398 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 399 url: str | None 400 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 401 width: int | None 402 "Width of the image in pixels. `null` if not known."
ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.
ID of the associated media record (med_...). null when the image is not linked to a media entity.
Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.
Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.
405class MessageUpdatedPayloadMessageAttachmentsItemVariantsItemImageSource(TypedDict, total=False): 406 file: str | None 407 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 408 height: int | None 409 "Height of the image in pixels. `null` if not known." 410 media: str | None 411 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 412 mime_type: str | None 413 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 414 refresh_url: str | None 415 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 416 url: str | None 417 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 418 width: int | None 419 "Width of the image in pixels. `null` if not known."
ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.
ID of the associated media record (med_...). null when the image is not linked to a media entity.
Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.
Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.
422class MessageUpdatedPayloadMessageAttachmentsItemVariantsItem(TypedDict, total=False): 423 content_type: str | None 424 'MIME type of this variant\'s file (e.g., `"image/jpeg"`, `"video/mp4"`). `null` if the file is not loaded.' 425 created_at: datetime | None 426 "When this variant was created (ISO 8601)." 427 file: str | None 428 "ID of the underlying storage file that backs this variant (`fil_...`)." 429 filename: str | None 430 "Original filename of the uploaded file for this variant. `null` if the file is not loaded." 431 height: int | None 432 "Height of this variant in pixels. `null` if not recorded." 433 id: Required[str] 434 "Media variant ID (`mvr_...`)." 435 image_source: MessageUpdatedPayloadMessageAttachmentsItemVariantsItemImageSource | None 436 "Resolved image delivery metadata for this variant, including dimensions and CDN URL. `null` for non-image content types." 437 updated_at: datetime | None 438 "When this variant was last updated (ISO 8601)." 439 url: str | None 440 "Signed download URL for this variant, resolved at request time. `null` if the file is unavailable." 441 variant_key: str | None 442 'Identifier for this variant\'s processing tier. Common values include `"original"` (the unmodified upload) and `"thumbnail"` (a resized preview).' 443 width: int | None 444 "Width of this variant in pixels. `null` if not recorded."
MIME type of this variant's file (e.g., "image/jpeg", "video/mp4"). null if the file is not loaded.
Original filename of the uploaded file for this variant. null if the file is not loaded.
Resolved image delivery metadata for this variant, including dimensions and CDN URL. null for non-image content types.
Signed download URL for this variant, resolved at request time. null if the file is unavailable.
447class MessageUpdatedPayloadMessageAttachmentsItem(TypedDict, total=False): 448 content_type: str | None 449 'MIME type of the attached file, e.g. `"image/png"` or `"application/pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.' 450 description: str | None 451 "Short description. The page meta-description for `scraped_link`, the artifact description for `artifact`, and the task description for `task` types. `null` on other types." 452 filename: str | None 453 'Original filename of the attached file, e.g. `"report.pdf"`. Present on `file`, `artifact`, and `media` types. `null` otherwise.' 454 height: int | None 455 "Height in pixels of the media item. Present on `media` type only. `null` otherwise." 456 id: Required[str] 457 "Unique identifier for this attachment within the message." 458 image_height: int | None 459 "Height in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise." 460 image_source: MessageUpdatedPayloadMessageAttachmentsItemImageSource | None 461 "Image source metadata for inline rendering. Present on `file`, `scraped_link`, `artifact`, and `media` types when the content is an image. `null` otherwise." 462 image_url: str | None 463 "URL of the preview image extracted from the scraped page. Present on `scraped_link` type only. `null` otherwise." 464 image_width: int | None 465 "Width in pixels of the scraped preview image. Present on `scraped_link` type only. `null` otherwise." 466 media_type: str | None 467 'The media category, e.g. `"video"` or `"audio"`. Present on `media` type only; omitted otherwise.' 468 name: str | None 469 "Display name of the media item. Present on `media` type only. `null` otherwise." 470 object: dict[str, Any] | None 471 "The full embedded object payload. For `task` type, contains the task record. For `action` type, contains the action definition. For `chart` type, contains the chart with its inline `spec`. Omitted on other types." 472 title: str | None 473 "Display title. The page title for `scraped_link`, the artifact name for `artifact`, and the task title for `task` types. `null` on other types." 474 type: Required[str] 475 'The attachment type. One of `"file"`, `"scraped_link"`, `"artifact"`, `"task"`, `"media"`, `"action"`, or `"chart"`. Determines which additional fields are present.' 476 url: str | None 477 "URL to access the resource. A signed download URL for `file` and `artifact` types; the original URL for `scraped_link`; a media playback URL for `media`. `null` on `task` and `action` types." 478 variants: list[MessageUpdatedPayloadMessageAttachmentsItemVariantsItem] | None 479 "Array of available encoding variants for the media item (e.g. different resolutions). Present on `media` type only; omitted otherwise." 480 version: int | None 481 "Version number of the attached artifact at the time of attachment. Present on `artifact` type only. `null` otherwise." 482 width: int | None 483 "Width in pixels of the media item. Present on `media` type only. `null` otherwise."
MIME type of the attached file, e.g. "image/png" or "application/pdf". Present on file, artifact, and media types. null otherwise.
Short description. The page meta-description for scraped_link, the artifact description for artifact, and the task description for task types. null on other types.
Original filename of the attached file, e.g. "report.pdf". Present on file, artifact, and media types. null otherwise.
Height in pixels of the scraped preview image. Present on scraped_link type only. null otherwise.
Image source metadata for inline rendering. Present on file, scraped_link, artifact, and media types when the content is an image. null otherwise.
URL of the preview image extracted from the scraped page. Present on scraped_link type only. null otherwise.
Width in pixels of the scraped preview image. Present on scraped_link type only. null otherwise.
The media category, e.g. "video" or "audio". Present on media type only; omitted otherwise.
The full embedded object payload. For task type, contains the task record. For action type, contains the action definition. For chart type, contains the chart with its inline spec. Omitted on other types.
Display title. The page title for scraped_link, the artifact name for artifact, and the task title for task types. null on other types.
The attachment type. One of "file", "scraped_link", "artifact", "task", "media", "action", or "chart". Determines which additional fields are present.
URL to access the resource. A signed download URL for file and artifact types; the original URL for scraped_link; a media playback URL for media. null on task and action types.
Array of available encoding variants for the media item (e.g. different resolutions). Present on media type only; omitted otherwise.
486class MessageUpdatedPayloadMessageReactionsItem(TypedDict, total=False): 487 payload: dict[str, Any] | None 488 'Type-specific reaction data. For `"emoji_reaction"` reactions, contains an `emoji` key with the Unicode emoji string (e.g., `" "`).' 489 type: Required[str] 490 'Reaction type identifier. Currently always `"emoji_reaction"` for emoji-based reactions.' 491 user: str | None 492 "Public ID of the user who added the reaction (`usr_...`)."
Type-specific reaction data. For "emoji_reaction" reactions, contains an emoji key with the Unicode emoji string (e.g., " ").
495class MessageUpdatedPayloadMessage(TypedDict, total=False): 496 acl: MessageUpdatedPayloadMessageAcl | None 497 "Access control list for private messages (grants with `read` action). Only returned to resource owners (and privileged/org-admin viewers) via server-side `field_redactions: [acl: :owner]`; `null` for everyone else." 498 actors: list[MessageUpdatedPayloadMessageActorsItem] | None 499 "Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry." 500 agent: str | None 501 "ID of the agent user that sent this message (`agi_...`). `null` for messages sent by human users." 502 agent_mode: Literal["cli", "embedded"] | None 503 "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." 504 attachments: list[MessageUpdatedPayloadMessageAttachmentsItem] | None 505 "Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments." 506 branched_thread: str | None 507 "ID of the thread that was branched from this message (`thr_...`). `null` if this message has not spawned a branch thread." 508 content: str | None 509 "Text content of the message. `null` for messages that contain only attachments." 510 created_at: str | None 511 "When the message was posted (ISO 8601)." 512 has_replies: bool | None 513 "Whether this message has at least one reply. Only present when explicitly requested or computed by the server." 514 id: Required[str] 515 "Message ID (`msg_...`)." 516 idempotency_key: str | None 517 "Client-supplied idempotency key used to deduplicate message sends. `null` if the sender did not provide one." 518 is_deleted: bool | None 519 "Whether this message is a deletion tombstone. `true` only on the `message_updated` broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always `false` for live messages." 520 legacy_agent: str | None 521 "Identifier of the legacy chat agent that sent this message, if applicable. `null` for messages sent by users or modern agent users." 522 metadata: dict[str, Any] | None 523 "Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set." 524 org: str | None 525 "ID of the organization that owns this message (`org_...`)." 526 reactions: list[MessageUpdatedPayloadMessageReactionsItem] | None 527 "Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded." 528 rendering_mode: str | None 529 'Display hint for how the message should be rendered. One of `"reply"`, `"direct"`, or `"inline"`. `null` for user-authored messages, which are always rendered as standard replies.' 530 replies: list[dict[str, Any]] | None 531 "Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message." 532 replies_after_cursor: str | None 533 "Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response." 534 replies_before_cursor: str | None 535 "Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response." 536 reply_count: int | None 537 "Total number of direct replies to this message. Only present when explicitly requested or computed by the server." 538 reply_to: dict[str, Any] | None 539 "The parent message this message is a reply to, expanded as a full message object when loaded. `null` if this is a top-level message or the association is not preloaded." 540 root_message_id: str | None 541 "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." 542 sandbox: str | None 543 "ID of the developer sandbox this message belongs to (`dsb_...`). `null` for non-sandbox messages." 544 team: str | None 545 "ID of the team this message is scoped to (`tem_...`). `null` if the message is not team-scoped." 546 thread: str | None 547 "ID of the thread this message belongs to (`thr_...`)." 548 type: str | None 549 "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." 550 user: str | dict[str, Any] | None 551 "The human user who sent this message. Returns a public ID string (`usr_...`) when the association is not preloaded, or an expanded user object when it is. `null` for messages sent by agents." 552 visibility: Literal["default", "private"] | None 553 "Message-level visibility. `default` is visible to anyone who can see the parent thread. `private` is restricted to the sender and explicit ACL `read` grantees."
Access control list for private messages (grants with read action). Only returned to resource owners (and privileged/org-admin viewers) via server-side field_redactions: [acl: :owner]; null for everyone else.
Resolved actor descriptors for the message sender, combining identity and display metadata. Always contains exactly one entry.
ID of the agent user that sent this message (agi_...). null for messages sent by human users.
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.
Files, links, tasks, media, artifacts, and actions attached to this message. Empty array if there are no attachments.
ID of the thread that was branched from this message (thr_...). null if this message has not spawned a branch thread.
Whether this message has at least one reply. Only present when explicitly requested or computed by the server.
Client-supplied idempotency key used to deduplicate message sends. null if the sender did not provide one.
Whether this message is a deletion tombstone. true only on the message_updated broadcast emitted when a message is deleted: the original content is replaced with a placeholder and the message no longer exists on the server. Always false for live messages.
Identifier of the legacy chat agent that sent this message, if applicable. null for messages sent by users or modern agent users.
Arbitrary key-value metadata attached to the message. Always present; defaults to an empty object when no metadata has been set.
Emoji and other reactions added to this message by users. Empty array if no reactions have been added or the association is not preloaded.
Display hint for how the message should be rendered. One of "reply", "direct", or "inline". null for user-authored messages, which are always rendered as standard replies.
Inline array of reply messages, each serialized as a full message object. Only present when the server has preloaded replies for this message.
Opaque pagination cursor to fetch replies posted after the current page. Only present when inline replies are included in the response.
Opaque pagination cursor to fetch replies posted before the current page. Only present when inline replies are included in the response.
Total number of direct replies to this message. Only present when explicitly requested or computed by the server.
The parent message this message is a reply to, expanded as a full message object when loaded. null if this is a top-level message or the association is not preloaded.
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.
ID of the developer sandbox this message belongs to (dsb_...). null for non-sandbox messages.
ID of the team this message is scoped to (tem_...). null if the message is not team-scoped.
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.
556class MessageUpdatedPayload(TypedDict, total=False): 557 "Broadcast when a message is updated or removed" 558 559 message: MessageUpdatedPayloadMessage | None 560 "A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata." 561 thread_id: str | None
Broadcast when a message is updated or removed
A chat message posted in a thread, including its content, author, attachments, reactions, and optional reply metadata.
564class ThreadEventPayload(TypedDict, total=False): 565 "Broadcast thread-level events (agent updates, read state, unread counts)" 566 567 payload: dict[str, Any] | None 568 thread_id: str | None 569 type: str | None
Broadcast thread-level events (agent updates, read state, unread counts)
572class SystemEventPayload(TypedDict, total=False): 573 "Broadcast system-wide events" 574 575 event: dict[str, Any] | None
Broadcast system-wide events
578class TypingPayloadActorProfilePicture(TypedDict, total=False): 579 file: str | None 580 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 581 height: int | None 582 "Height of the image in pixels. `null` if not known." 583 media: str | None 584 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 585 mime_type: str | None 586 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 587 refresh_url: str | None 588 "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing." 589 url: str | None 590 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 591 width: int | None 592 "Width of the image in pixels. `null` if not known."
ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.
ID of the associated media record (med_...). null when the image is not linked to a media entity.
Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.
Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.
595class TypingPayloadActor(TypedDict, total=False): 596 alias: str | None 597 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 598 id: str | None 599 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 600 name: str | None 601 "Display name of the actor shown in the UI. `null` if no name is set." 602 profile_picture: TypingPayloadActorProfilePicture | None 603 "Profile picture for the actor. `null` if the actor has no profile picture."
Short handle or alias for the actor, used as an alternate display identifier. null if not configured.
Composite actor identifier. Format is "user-<usr_...>" for human users or "agent-<agi_...>" for agents.
Profile picture for the actor. null if the actor has no profile picture.
606class TypingPayload(TypedDict, total=False): 607 "Broadcast when a participant (human or agent) starts or stops typing. Ephemeral; never persisted." 608 609 actor: TypingPayloadActor | None 610 "The entity that authored a message, either a human user or an agent." 611 is_typing: bool | None 612 thread_id: str | None
Broadcast when a participant (human or agent) starts or stops typing. Ephemeral; never persisted.
The entity that authored a message, either a human user or an agent.
618class ApiChatChannel: 619 def __init__(self, channel, join_response=None): 620 self._channel = channel 621 self.join_response = join_response 622 623 # Join a team-scoped thread by ID 624 @staticmethod 625 def topic_team_thread(team_id: str, thread_id: str) -> str: 626 return f"api:chat:team:{team_id}:thread:{thread_id}" 627 628 # Join a team-scoped thread by ID 629 @classmethod 630 async def join_team_thread( 631 cls, 632 socket: "Socket", 633 team_id: str, 634 thread_id: str, 635 *, 636 after_cursor: str | None = None, 637 before_cursor: str | None = None, 638 include_metadata: bool | None = None, 639 limit: int | None = None, 640 ) -> "ApiChatChannel": 641 topic = cls.topic_team_thread(team_id, thread_id) 642 channel = socket.channel(topic) 643 payload: dict[str, object] = {} 644 if after_cursor is not None: 645 payload["after_cursor"] = after_cursor 646 if before_cursor is not None: 647 payload["before_cursor"] = before_cursor 648 if include_metadata is not None: 649 payload["include_metadata"] = include_metadata 650 if limit is not None: 651 payload["limit"] = limit 652 join_response = await channel.join(payload) 653 return cls(channel, join_response) 654 655 # Join or create a team-scoped keyed thread 656 @staticmethod 657 def topic_team_keyed(team_id: str, key: str) -> str: 658 return f"api:chat:team:{team_id}:key:{key}" 659 660 # Join or create a team-scoped keyed thread 661 @classmethod 662 async def join_team_keyed( 663 cls, 664 socket: "Socket", 665 team_id: str, 666 key: str, 667 *, 668 after_cursor: str | None = None, 669 before_cursor: str | None = None, 670 include_metadata: bool | None = None, 671 limit: int | None = None, 672 ) -> "ApiChatChannel": 673 topic = cls.topic_team_keyed(team_id, key) 674 channel = socket.channel(topic) 675 payload: dict[str, object] = {} 676 if after_cursor is not None: 677 payload["after_cursor"] = after_cursor 678 if before_cursor is not None: 679 payload["before_cursor"] = before_cursor 680 if include_metadata is not None: 681 payload["include_metadata"] = include_metadata 682 if limit is not None: 683 payload["limit"] = limit 684 join_response = await channel.join(payload) 685 return cls(channel, join_response) 686 687 # Join a team-scoped transient (ephemeral) thread 688 @staticmethod 689 def topic_team_transient(team_id: str, key: str) -> str: 690 return f"api:chat:team:{team_id}:transient:{key}" 691 692 # Join a team-scoped transient (ephemeral) thread 693 @classmethod 694 async def join_team_transient( 695 cls, 696 socket: "Socket", 697 team_id: str, 698 key: str, 699 *, 700 after_cursor: str | None = None, 701 before_cursor: str | None = None, 702 include_metadata: bool | None = None, 703 limit: int | None = None, 704 ) -> "ApiChatChannel": 705 topic = cls.topic_team_transient(team_id, key) 706 channel = socket.channel(topic) 707 payload: dict[str, object] = {} 708 if after_cursor is not None: 709 payload["after_cursor"] = after_cursor 710 if before_cursor is not None: 711 payload["before_cursor"] = before_cursor 712 if include_metadata is not None: 713 payload["include_metadata"] = include_metadata 714 if limit is not None: 715 payload["limit"] = limit 716 join_response = await channel.join(payload) 717 return cls(channel, join_response) 718 719 # Join a user-scoped thread by ID, optionally supplying local tools for a personal thread 720 @staticmethod 721 def topic_user_thread(thread_id: str) -> str: 722 return f"api:chat:user:thread:{thread_id}" 723 724 # Join a user-scoped thread by ID, optionally supplying local tools for a personal thread 725 @classmethod 726 async def join_user_thread( 727 cls, 728 socket: "Socket", 729 thread_id: str, 730 *, 731 after_cursor: str | None = None, 732 before_cursor: str | None = None, 733 include_metadata: bool | None = None, 734 limit: int | None = None, 735 local_tool_provider_id: str | None = None, 736 local_tools: list[dict[str, Any]] | None = None, 737 ) -> "ApiChatChannel": 738 topic = cls.topic_user_thread(thread_id) 739 channel = socket.channel(topic) 740 payload: dict[str, object] = {} 741 if after_cursor is not None: 742 payload["after_cursor"] = after_cursor 743 if before_cursor is not None: 744 payload["before_cursor"] = before_cursor 745 if include_metadata is not None: 746 payload["include_metadata"] = include_metadata 747 if limit is not None: 748 payload["limit"] = limit 749 if local_tool_provider_id is not None: 750 payload["local_tool_provider_id"] = local_tool_provider_id 751 if local_tools is not None: 752 payload["local_tools"] = local_tools 753 join_response = await channel.join(payload) 754 return cls(channel, join_response) 755 756 # Join or create a user-scoped keyed thread 757 @staticmethod 758 def topic_user_keyed(key: str) -> str: 759 return f"api:chat:user:key:{key}" 760 761 # Join or create a user-scoped keyed thread 762 @classmethod 763 async def join_user_keyed( 764 cls, 765 socket: "Socket", 766 key: str, 767 *, 768 after_cursor: str | None = None, 769 before_cursor: str | None = None, 770 include_metadata: bool | None = None, 771 limit: int | None = None, 772 ) -> "ApiChatChannel": 773 topic = cls.topic_user_keyed(key) 774 channel = socket.channel(topic) 775 payload: dict[str, object] = {} 776 if after_cursor is not None: 777 payload["after_cursor"] = after_cursor 778 if before_cursor is not None: 779 payload["before_cursor"] = before_cursor 780 if include_metadata is not None: 781 payload["include_metadata"] = include_metadata 782 if limit is not None: 783 payload["limit"] = limit 784 join_response = await channel.join(payload) 785 return cls(channel, join_response) 786 787 # Join a user-scoped transient (ephemeral) thread 788 @staticmethod 789 def topic_user_transient(key: str) -> str: 790 return f"api:chat:user:transient:{key}" 791 792 # Join a user-scoped transient (ephemeral) thread 793 @classmethod 794 async def join_user_transient( 795 cls, 796 socket: "Socket", 797 key: str, 798 *, 799 after_cursor: str | None = None, 800 before_cursor: str | None = None, 801 include_metadata: bool | None = None, 802 limit: int | None = None, 803 ) -> "ApiChatChannel": 804 topic = cls.topic_user_transient(key) 805 channel = socket.channel(topic) 806 payload: dict[str, object] = {} 807 if after_cursor is not None: 808 payload["after_cursor"] = after_cursor 809 if before_cursor is not None: 810 payload["before_cursor"] = before_cursor 811 if include_metadata is not None: 812 payload["include_metadata"] = include_metadata 813 if limit is not None: 814 payload["limit"] = limit 815 join_response = await channel.join(payload) 816 return cls(channel, join_response) 817 818 # Leave the underlying channel. 819 async def leave(self): 820 await self._channel.leave() 821 822 # Fork a sub-thread from an existing message 823 async def api_chat_fork_thread(self, payload: ApiChatForkThreadInput) -> dict[str, Any]: 824 return await self._channel.push("api:chat:fork_thread", payload) 825 826 # Mark a thread as read up to a given message 827 async def api_chat_mark_thread_read( 828 self, payload: ApiChatMarkThreadReadInput 829 ) -> dict[str, Any]: 830 return await self._channel.push("api:chat:mark_thread_read", payload) 831 832 # List all messages in the current thread 833 async def api_chat_list_messages(self, payload: dict) -> dict[str, Any]: 834 return await self._channel.push("api:chat:list_messages", payload) 835 836 # Load additional messages with cursor-based pagination 837 async def api_chat_load_more_messages( 838 self, payload: ApiChatLoadMoreMessagesInput 839 ) -> dict[str, Any]: 840 return await self._channel.push("api:chat:load_more_messages", payload) 841 842 # Post a new message with optional uploads and reply-to 843 async def api_chat_post_message(self, payload: ApiChatPostMessageInput) -> dict[str, Any]: 844 return await self._channel.push("api:chat:post_message", payload) 845 846 # Post a simple text message 847 async def api_chat_post_simple_message( 848 self, payload: ApiChatPostSimpleMessageInput 849 ) -> dict[str, Any]: 850 return await self._channel.push("api:chat:post_simple_message", payload) 851 852 # Edit an existing message's content 853 async def api_chat_edit_message(self, payload: ApiChatEditMessageInput) -> dict[str, Any]: 854 return await self._channel.push("api:chat:edit_message", payload) 855 856 # Delete a message 857 async def api_chat_delete_message(self, payload: ApiChatDeleteMessageInput) -> dict[str, Any]: 858 return await self._channel.push("api:chat:delete_message", payload) 859 860 # Add an emoji reaction to a message 861 async def api_chat_add_reaction(self, payload: ApiChatAddReactionInput) -> dict[str, Any]: 862 return await self._channel.push("api:chat:add_reaction", payload) 863 864 # Remove an emoji reaction from a message 865 async def api_chat_remove_reaction(self, payload: ApiChatRemoveReactionInput) -> dict[str, Any]: 866 return await self._channel.push("api:chat:remove_reaction", payload) 867 868 # Signal that the current user has started or stopped typing in the thread 869 async def api_chat_typing(self, payload: ApiChatTypingInput) -> dict[str, Any]: 870 return await self._channel.push("api:chat:typing", payload) 871 872 # Broadcast when a new message is added to a thread 873 def on_message_added( 874 self, callback: Callable[[MessageAddedPayload], None] 875 ) -> Callable[[], None]: 876 return self._channel.on("message_added", callback) 877 878 # Broadcast when a message is updated or removed 879 def on_message_updated( 880 self, callback: Callable[[MessageUpdatedPayload], None] 881 ) -> Callable[[], None]: 882 return self._channel.on("message_updated", callback) 883 884 # Broadcast thread-level events (agent updates, read state, unread counts) 885 def on_thread_event(self, callback: Callable[[ThreadEventPayload], None]) -> Callable[[], None]: 886 return self._channel.on("thread_event", callback) 887 888 # Broadcast system-wide events 889 def on_system_event(self, callback: Callable[[SystemEventPayload], None]) -> Callable[[], None]: 890 return self._channel.on("system_event", callback) 891 892 # Broadcast when a participant (human or agent) starts or stops typing. Ephemeral; never persisted. 893 def on_typing(self, callback: Callable[[TypingPayload], None]) -> Callable[[], None]: 894 return self._channel.on("typing", callback)
629 @classmethod 630 async def join_team_thread( 631 cls, 632 socket: "Socket", 633 team_id: str, 634 thread_id: str, 635 *, 636 after_cursor: str | None = None, 637 before_cursor: str | None = None, 638 include_metadata: bool | None = None, 639 limit: int | None = None, 640 ) -> "ApiChatChannel": 641 topic = cls.topic_team_thread(team_id, thread_id) 642 channel = socket.channel(topic) 643 payload: dict[str, object] = {} 644 if after_cursor is not None: 645 payload["after_cursor"] = after_cursor 646 if before_cursor is not None: 647 payload["before_cursor"] = before_cursor 648 if include_metadata is not None: 649 payload["include_metadata"] = include_metadata 650 if limit is not None: 651 payload["limit"] = limit 652 join_response = await channel.join(payload) 653 return cls(channel, join_response)
661 @classmethod 662 async def join_team_keyed( 663 cls, 664 socket: "Socket", 665 team_id: str, 666 key: str, 667 *, 668 after_cursor: str | None = None, 669 before_cursor: str | None = None, 670 include_metadata: bool | None = None, 671 limit: int | None = None, 672 ) -> "ApiChatChannel": 673 topic = cls.topic_team_keyed(team_id, key) 674 channel = socket.channel(topic) 675 payload: dict[str, object] = {} 676 if after_cursor is not None: 677 payload["after_cursor"] = after_cursor 678 if before_cursor is not None: 679 payload["before_cursor"] = before_cursor 680 if include_metadata is not None: 681 payload["include_metadata"] = include_metadata 682 if limit is not None: 683 payload["limit"] = limit 684 join_response = await channel.join(payload) 685 return cls(channel, join_response)
693 @classmethod 694 async def join_team_transient( 695 cls, 696 socket: "Socket", 697 team_id: str, 698 key: str, 699 *, 700 after_cursor: str | None = None, 701 before_cursor: str | None = None, 702 include_metadata: bool | None = None, 703 limit: int | None = None, 704 ) -> "ApiChatChannel": 705 topic = cls.topic_team_transient(team_id, key) 706 channel = socket.channel(topic) 707 payload: dict[str, object] = {} 708 if after_cursor is not None: 709 payload["after_cursor"] = after_cursor 710 if before_cursor is not None: 711 payload["before_cursor"] = before_cursor 712 if include_metadata is not None: 713 payload["include_metadata"] = include_metadata 714 if limit is not None: 715 payload["limit"] = limit 716 join_response = await channel.join(payload) 717 return cls(channel, join_response)
725 @classmethod 726 async def join_user_thread( 727 cls, 728 socket: "Socket", 729 thread_id: str, 730 *, 731 after_cursor: str | None = None, 732 before_cursor: str | None = None, 733 include_metadata: bool | None = None, 734 limit: int | None = None, 735 local_tool_provider_id: str | None = None, 736 local_tools: list[dict[str, Any]] | None = None, 737 ) -> "ApiChatChannel": 738 topic = cls.topic_user_thread(thread_id) 739 channel = socket.channel(topic) 740 payload: dict[str, object] = {} 741 if after_cursor is not None: 742 payload["after_cursor"] = after_cursor 743 if before_cursor is not None: 744 payload["before_cursor"] = before_cursor 745 if include_metadata is not None: 746 payload["include_metadata"] = include_metadata 747 if limit is not None: 748 payload["limit"] = limit 749 if local_tool_provider_id is not None: 750 payload["local_tool_provider_id"] = local_tool_provider_id 751 if local_tools is not None: 752 payload["local_tools"] = local_tools 753 join_response = await channel.join(payload) 754 return cls(channel, join_response)
762 @classmethod 763 async def join_user_keyed( 764 cls, 765 socket: "Socket", 766 key: str, 767 *, 768 after_cursor: str | None = None, 769 before_cursor: str | None = None, 770 include_metadata: bool | None = None, 771 limit: int | None = None, 772 ) -> "ApiChatChannel": 773 topic = cls.topic_user_keyed(key) 774 channel = socket.channel(topic) 775 payload: dict[str, object] = {} 776 if after_cursor is not None: 777 payload["after_cursor"] = after_cursor 778 if before_cursor is not None: 779 payload["before_cursor"] = before_cursor 780 if include_metadata is not None: 781 payload["include_metadata"] = include_metadata 782 if limit is not None: 783 payload["limit"] = limit 784 join_response = await channel.join(payload) 785 return cls(channel, join_response)
793 @classmethod 794 async def join_user_transient( 795 cls, 796 socket: "Socket", 797 key: str, 798 *, 799 after_cursor: str | None = None, 800 before_cursor: str | None = None, 801 include_metadata: bool | None = None, 802 limit: int | None = None, 803 ) -> "ApiChatChannel": 804 topic = cls.topic_user_transient(key) 805 channel = socket.channel(topic) 806 payload: dict[str, object] = {} 807 if after_cursor is not None: 808 payload["after_cursor"] = after_cursor 809 if before_cursor is not None: 810 payload["before_cursor"] = before_cursor 811 if include_metadata is not None: 812 payload["include_metadata"] = include_metadata 813 if limit is not None: 814 payload["limit"] = limit 815 join_response = await channel.join(payload) 816 return cls(channel, join_response)