archastro.platform.channels.api_tasks_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: 426450fa3df6 4 5from collections.abc import Callable 6from datetime import datetime 7from typing import TYPE_CHECKING, Any, Required, TypedDict 8 9if TYPE_CHECKING: 10 from archastro.phx_channel.socket import Socket 11 12 13class TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture(TypedDict, total=False): 14 file: str | None 15 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 16 height: int | None 17 "Height of the image in pixels. `null` if not known." 18 media: str | None 19 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 20 mime_type: str | None 21 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 22 refresh_url: str | None 23 "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." 24 url: str | None 25 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 26 width: int | None 27 "Width of the image in pixels. `null` if not known." 28 29 30class TasksUpdatedPayloadTasksItemCreatedByActor(TypedDict, total=False): 31 alias: str | None 32 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 33 id: str | None 34 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 35 name: str | None 36 "Display name of the actor shown in the UI. `null` if no name is set." 37 profile_picture: TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture | None 38 "Profile picture for the actor. `null` if the actor has no profile picture." 39 40 41class TasksUpdatedPayloadTasksItemCurrentLease(TypedDict): 42 expires_at: datetime 43 "Server-calculated lease expiry in ISO 8601 format." 44 harness: str 45 "Bounded harness identifier for the coding session." 46 session_name: str 47 "Display name supplied by the coding session that holds the lease." 48 49 50class TasksUpdatedPayloadTasksItemOwnerActorProfilePicture(TypedDict, total=False): 51 file: str | None 52 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 53 height: int | None 54 "Height of the image in pixels. `null` if not known." 55 media: str | None 56 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 57 mime_type: str | None 58 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 59 refresh_url: str | None 60 "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." 61 url: str | None 62 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 63 width: int | None 64 "Width of the image in pixels. `null` if not known." 65 66 67class TasksUpdatedPayloadTasksItemOwnerActor(TypedDict, total=False): 68 alias: str | None 69 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 70 id: str | None 71 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 72 name: str | None 73 "Display name of the actor shown in the UI. `null` if no name is set." 74 profile_picture: TasksUpdatedPayloadTasksItemOwnerActorProfilePicture | None 75 "Profile picture for the actor. `null` if the actor has no profile picture." 76 77 78class TasksUpdatedPayloadTasksItem(TypedDict, total=False): 79 agent: str | None 80 "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user." 81 blocked_by_count: int | None 82 "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind." 83 closed_at: datetime | None 84 "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open." 85 comments_count: int | None 86 "Total number of comments posted on this task." 87 created_at: datetime | None 88 "When the task was created (ISO 8601)." 89 created_by_actor: TasksUpdatedPayloadTasksItemCreatedByActor | None 90 "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted)." 91 created_by_agent: str | None 92 "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted." 93 created_by_user: str | None 94 "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted." 95 current_lease: TasksUpdatedPayloadTasksItemCurrentLease | None 96 "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included." 97 description: str | None 98 "Long-form description or notes for the task. `null` if no description has been provided." 99 due_date: datetime | None 100 "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set." 101 epic: str | None 102 "Free-form grouping label. `null` when the task is not in an epic." 103 id: Required[str] 104 "Task ID (`tsk_...`)." 105 is_blocked: bool | None 106 "`true` while at least one blocking task is not yet done. Informational only a blocked task can still change status and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read." 107 links: dict[str, Any] | None 108 "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set." 109 metadata: dict[str, Any] | None 110 "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set." 111 name: Required[str] 112 "Human-readable title of the task." 113 org: str | None 114 "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context." 115 owner_actor: TasksUpdatedPayloadTasksItemOwnerActor | None 116 "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted)." 117 owner_agent: str | None 118 "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted." 119 owner_user: str | None 120 "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted." 121 parent: str | None 122 "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level." 123 priority: int | None 124 "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set." 125 sandbox: str | None 126 "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment." 127 source_id: str | None 128 "Source object identity (for example `ArchAstro/firstlanding`). `null` when the task has no source." 129 source_scope: str | None 130 "Container of the work this task is about (for example `github.com`). `null` when the task has no source. Set together with `source_type` and `source_id`." 131 source_type: str | None 132 "Kind of source object (for example `repository`). `null` when the task has no source." 133 status: Required[str] 134 'Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`.' 135 subtasks_count: int | None 136 "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks." 137 tags: list[str] | None 138 "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged." 139 team: str | None 140 "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team." 141 thread: str | None 142 "ID of the thread this task is bound to (`thr_...`) the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread." 143 updated_at: datetime | None 144 "When the task was last modified (ISO 8601)." 145 user: str | None 146 "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team." 147 148 149class TasksUpdatedPayload(TypedDict, total=False): 150 "Broadcast when the thread's task records change; carries a full snapshot" 151 152 tasks: list[TasksUpdatedPayloadTasksItem] | None 153 154 155# Phoenix channel for live task-record updates. 156# Clients join `api:tasks:thread:{thread_id}` to receive the thread's current 157# event-sourced tasks and subscribe to changes. The join reply carries a full 158# snapshot (`%{tasks: [...]}`), and every subsequent change lands as a 159# `tasks_updated` push carrying a fresh snapshot the same replace-wholesale 160# contract expected by task-panel clients, so clients need no 161# delta bookkeeping. 162# Change signals originate from `ArchAstro.Tasks.Projectors.TaskProjector`, 163# which broadcasts on `"tasks:thread:{thread_id}"` after each committed 164# projection. Bursts (e.g. a mirror reconcile dispatching several commands) 165# are coalesced: the first signal arms a short timer and the reload happens 166# once, after the burst settles. 167class ApiTasksChannel: 168 def __init__(self, channel, join_response=None): 169 self._channel = channel 170 self.join_response = join_response 171 172 # Join a thread's live task list 173 @staticmethod 174 def topic_thread(thread_id: str) -> str: 175 return f"api:tasks:thread:{thread_id}" 176 177 # Join a thread's live task list 178 @classmethod 179 async def join_thread(cls, socket: "Socket", thread_id: str) -> "ApiTasksChannel": 180 topic = cls.topic_thread(thread_id) 181 channel = socket.channel(topic) 182 join_response = await channel.join() 183 return cls(channel, join_response) 184 185 # Leave the underlying channel. 186 async def leave(self): 187 await self._channel.leave() 188 189 # Broadcast when the thread's task records change; carries a full snapshot 190 def on_tasks_updated( 191 self, callback: Callable[[TasksUpdatedPayload], None] 192 ) -> Callable[[], None]: 193 return self._channel.on("tasks_updated", callback)
14class TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture(TypedDict, total=False): 15 file: str | None 16 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 17 height: int | None 18 "Height of the image in pixels. `null` if not known." 19 media: str | None 20 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 21 mime_type: str | None 22 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 23 refresh_url: str | None 24 "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." 25 url: str | None 26 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 27 width: int | None 28 "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.
31class TasksUpdatedPayloadTasksItemCreatedByActor(TypedDict, total=False): 32 alias: str | None 33 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 34 id: str | None 35 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 36 name: str | None 37 "Display name of the actor shown in the UI. `null` if no name is set." 38 profile_picture: TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture | None 39 "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.
42class TasksUpdatedPayloadTasksItemCurrentLease(TypedDict): 43 expires_at: datetime 44 "Server-calculated lease expiry in ISO 8601 format." 45 harness: str 46 "Bounded harness identifier for the coding session." 47 session_name: str 48 "Display name supplied by the coding session that holds the lease."
51class TasksUpdatedPayloadTasksItemOwnerActorProfilePicture(TypedDict, total=False): 52 file: str | None 53 "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file." 54 height: int | None 55 "Height of the image in pixels. `null` if not known." 56 media: str | None 57 "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity." 58 mime_type: str | None 59 'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.' 60 refresh_url: str | None 61 "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." 62 url: str | None 63 "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires." 64 width: int | None 65 "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.
68class TasksUpdatedPayloadTasksItemOwnerActor(TypedDict, total=False): 69 alias: str | None 70 "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured." 71 id: str | None 72 'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.' 73 name: str | None 74 "Display name of the actor shown in the UI. `null` if no name is set." 75 profile_picture: TasksUpdatedPayloadTasksItemOwnerActorProfilePicture | None 76 "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.
79class TasksUpdatedPayloadTasksItem(TypedDict, total=False): 80 agent: str | None 81 "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user." 82 blocked_by_count: int | None 83 "Number of tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind." 84 closed_at: datetime | None 85 "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open." 86 comments_count: int | None 87 "Total number of comments posted on this task." 88 created_at: datetime | None 89 "When the task was created (ISO 8601)." 90 created_by_actor: TasksUpdatedPayloadTasksItemCreatedByActor | None 91 "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted)." 92 created_by_agent: str | None 93 "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted." 94 created_by_user: str | None 95 "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted." 96 current_lease: TasksUpdatedPayloadTasksItemCurrentLease | None 97 "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included." 98 description: str | None 99 "Long-form description or notes for the task. `null` if no description has been provided." 100 due_date: datetime | None 101 "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set." 102 epic: str | None 103 "Free-form grouping label. `null` when the task is not in an epic." 104 id: Required[str] 105 "Task ID (`tsk_...`)." 106 is_blocked: bool | None 107 "`true` while at least one blocking task is not yet done. Informational only a blocked task can still change status and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report `false` until the next read." 108 links: dict[str, Any] | None 109 "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set." 110 metadata: dict[str, Any] | None 111 "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set." 112 name: Required[str] 113 "Human-readable title of the task." 114 org: str | None 115 "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context." 116 owner_actor: TasksUpdatedPayloadTasksItemOwnerActor | None 117 "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted)." 118 owner_agent: str | None 119 "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted." 120 owner_user: str | None 121 "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted." 122 parent: str | None 123 "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks. Subtasks nest exactly one level." 124 priority: int | None 125 "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set." 126 sandbox: str | None 127 "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment." 128 source_id: str | None 129 "Source object identity (for example `ArchAstro/firstlanding`). `null` when the task has no source." 130 source_scope: str | None 131 "Container of the work this task is about (for example `github.com`). `null` when the task has no source. Set together with `source_type` and `source_id`." 132 source_type: str | None 133 "Kind of source object (for example `repository`). `null` when the task has no source." 134 status: Required[str] 135 'Current status of the task. One of `"open"`, `"in_progress"`, or `"done"`.' 136 subtasks_count: int | None 137 "Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks." 138 tags: list[str] | None 139 "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged." 140 team: str | None 141 "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team." 142 thread: str | None 143 "ID of the thread this task is bound to (`thr_...`) the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread." 144 updated_at: datetime | None 145 "When the task was last modified (ISO 8601)." 146 user: str | None 147 "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team."
ID of the agent that owns this task (agi_...). null if the task is scoped to a team or user.
Number of tasks marked as blocking this task, whether or not they are done (see GET /tasks/{task}/blockers). Computed on list/show reads; create/update responses may lag one read behind.
When the task was marked as done or otherwise closed (ISO 8601). null if the task is still open.
ID of the agent that created this task (agi_...). null if the task was created by a human user, or if the creating agent was later deleted.
ID of the user who created this task (usr_...). null if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.
Viewer-safe live coding-session lease summary. null when the task is unleased or the projected lease has expired. Fencing identifiers are never included.
Long-form description or notes for the task. null if no description has been provided.
Date and time by which the task should be completed (ISO 8601). null if no due date is set.
true while at least one blocking task is not yet done. Informational only a blocked task can still change status and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on list/show reads; create/update responses report false until the next read.
Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set.
Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.
ID of the organization this task belongs to (org_...). null for tasks outside an org context.
ID of the agent assigned as owner (agi_...). null if the owner is a human user, the task is unassigned, or the assigned agent was deleted.
ID of the user assigned as owner (usr_...). null if the owner is an agent, the task is unassigned, or the assigned agent was deleted.
ID of the parent task when this task is a subtask (tsk_...). null for top-level tasks. Subtasks nest exactly one level.
Priority level of the task from 0 (highest) to 4 (lowest). Defaults to 2 (medium) when not explicitly set.
ID of the developer sandbox this task is scoped to (dsb_...). null for tasks outside a sandbox environment.
Source object identity (for example ArchAstro/firstlanding). null when the task has no source.
Container of the work this task is about (for example github.com). null when the task has no source. Set together with source_type and source_id.
Kind of source object (for example repository). null when the task has no source.
Number of subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.
ID of the team that owns this task (tem_...). null if the task is not scoped to a team.
150class TasksUpdatedPayload(TypedDict, total=False): 151 "Broadcast when the thread's task records change; carries a full snapshot" 152 153 tasks: list[TasksUpdatedPayloadTasksItem] | None
Broadcast when the thread's task records change; carries a full snapshot
168class ApiTasksChannel: 169 def __init__(self, channel, join_response=None): 170 self._channel = channel 171 self.join_response = join_response 172 173 # Join a thread's live task list 174 @staticmethod 175 def topic_thread(thread_id: str) -> str: 176 return f"api:tasks:thread:{thread_id}" 177 178 # Join a thread's live task list 179 @classmethod 180 async def join_thread(cls, socket: "Socket", thread_id: str) -> "ApiTasksChannel": 181 topic = cls.topic_thread(thread_id) 182 channel = socket.channel(topic) 183 join_response = await channel.join() 184 return cls(channel, join_response) 185 186 # Leave the underlying channel. 187 async def leave(self): 188 await self._channel.leave() 189 190 # Broadcast when the thread's task records change; carries a full snapshot 191 def on_tasks_updated( 192 self, callback: Callable[[TasksUpdatedPayload], None] 193 ) -> Callable[[], None]: 194 return self._channel.on("tasks_updated", callback)