Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/hooks/tools.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -808,11 +808,11 @@ If a value is too large for the environment, it may be omitted (not set). Xum al
<details>
<summary>task_send_message (3)</summary>

| Env var | JSON path | Type | Description |
| ------------------------------------ | --------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `XUM_TOOL_INPUT_MESSAGE` | `message` | string | Plain-text message to deliver to the target. Sibling/upward sends are capped at 16384 characters and draw from shared per-pair/per-target session budgets; descendant guidance is uncapped. |
| `XUM_TOOL_INPUT_QUEUE_DISPATCH_MODE` | `queue_dispatch_mode` | enum | When the target is busy, dispatch at "tool-end" after its next tool call or at "turn-end" after its current turn. Defaults to "tool-end" for descendant and sibling targets and "turn-end" for ancestor and unrelated targets (often human-driven; do not cut into their active turn). |
| `XUM_TOOL_INPUT_TASK_ID` | `task_id` | string | Target workspace ID: a descendant sub-agent task ID returned by task, a same-tree row from task_list scope:"tree" (peer, ancestor, or root), an opted-in root workspace row from task_list scope:"instance", or any other workspace ID in this Xum instance that you already know β€” an envelope "from" reply address or an ID the user provided. Unrelated (cross-tree) targets may be root workspaces or live sub-agents of other trees, but both sender and target must use local or worktree runtimes and the actual recipient must opt in through its workspace settings. |
| Env var | JSON path | Type | Description |
| ------------------------------------ | --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `XUM_TOOL_INPUT_MESSAGE` | `message` | string | Plain-text message to deliver to the target. Sibling/upward sends are capped at 16384 characters and draw from shared per-pair/per-target session budgets; descendant guidance is uncapped. |
| `XUM_TOOL_INPUT_QUEUE_DISPATCH_MODE` | `queue_dispatch_mode` | enum | When the target is busy, dispatch at "tool-end" after its next tool call or at "turn-end" after its current turn. Defaults to "tool-end" for descendant and sibling targets and "turn-end" for ancestor and unrelated targets (often human-driven; do not cut into their active turn). |
| `XUM_TOOL_INPUT_TASK_ID` | `task_id` | string | Target workspace ID: a descendant sub-agent task ID returned by task, a same-tree row from task_list scope:"tree" (peer, ancestor, or root), an opted-in root workspace row from task_list scope:"instance", or any other workspace ID in this Xum instance that you already know β€” an envelope "from" reply address or an ID the user provided. Unrelated (cross-tree) targets may be root workspaces or live sub-agents of other trees, but both sender and target must use local or worktree runtimes and the actual recipient must have consented (newly created root workspaces other than task(kind:"workspace") targets are opted in by default; others enable it in their workspace settings). |

</details>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ export function WorkspaceUnrelatedMessagingModal(props: WorkspaceUnrelatedMessag
</div>
<DialogDescription className="text-muted mt-1 text-xs">
Applies to agents in other local chats in this Xum instance, outside this
chat&apos;s task tree. Off by default; same-tree sub-agents are unaffected.
chat&apos;s task tree. On by default for new chats you create; same-tree
sub-agents are unaffected.
</DialogDescription>
</div>
<div className="flex shrink-0 items-center gap-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export const Desktop: AppStory = {
play: async ({ canvasElement }) => {
const dialog = await openConsentDialog(canvasElement);
const toggle = within(dialog).getByRole("switch");
// Off by default: a fresh workspace has never consented.
// A workspace without a generation (created before the on-by-default change, or turned off)
// starts off.
if (toggle.getAttribute("aria-checked") !== "false") {
throw new Error("consent switch must start off for a workspace without a generation");
}
Expand Down
7 changes: 4 additions & 3 deletions src/common/orpc/schemas/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,13 @@ export const WorkflowTaskMetadataSchema = z.object({
* Shared description for the recipient-consent field on persisted config and published metadata.
* The value is an opaque revocation GENERATION, not a bearer credential: the sender never supplies
* it; the backend compares the generation captured at admission with the current one so an
* off→on flip cannot revive work queued under the previous consent. Absent means off. Only the
* app's settings surface writes it β€” same-UID processes with config access can too, so it is an
* off→on flip cannot revive work queued under the previous consent. Absent means off. New root
* workspaces (other than task-delegated targets) get a fresh generation once their creation setup
* is complete (on by default); the app's settings surface writes it β€” same-UID processes with config access can too, so it is an
* application-level opt-in, not an isolation boundary.
*/
export const UNRELATED_WORKSPACE_CONSENT_DESCRIPTION =
"Opaque consent generation allowing unrelated local workspaces (other task trees in this Xum instance) to discover this workspace and send it untrusted agent messages. Absent means off; each off→on transition mints a new value, and an already-on workspace keeps its value. Never a bearer credential.";
"Opaque consent generation allowing unrelated local workspaces (other task trees in this Xum instance) to discover this workspace and send it untrusted agent messages. New root workspaces (other than task-delegated targets) start with one; absent means off; each off→on transition mints a new value, and an already-on workspace keeps its value. Never a bearer credential.";

/**
* Fail-closed reader for the persisted consent generation. Config entries are loaded without
Expand Down
6 changes: 3 additions & 3 deletions src/common/utils/tools/toolDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,7 @@ export const TaskSendMessageToolArgsSchema = z
.string()
.min(1)
.describe(
'Target workspace ID: a descendant sub-agent task ID returned by task, a same-tree row from task_list scope:"tree" (peer, ancestor, or root), an opted-in root workspace row from task_list scope:"instance", or any other workspace ID in this Xum instance that you already know β€” an envelope "from" reply address or an ID the user provided. Unrelated (cross-tree) targets may be root workspaces or live sub-agents of other trees, but both sender and target must use local or worktree runtimes and the actual recipient must opt in through its workspace settings.'
'Target workspace ID: a descendant sub-agent task ID returned by task, a same-tree row from task_list scope:"tree" (peer, ancestor, or root), an opted-in root workspace row from task_list scope:"instance", or any other workspace ID in this Xum instance that you already know β€” an envelope "from" reply address or an ID the user provided. Unrelated (cross-tree) targets may be root workspaces or live sub-agents of other trees, but both sender and target must use local or worktree runtimes and the actual recipient must have consented (newly created root workspaces other than task(kind:"workspace") targets are opted in by default; others enable it in their workspace settings).'
),
message: z
.string()
Expand Down Expand Up @@ -3154,7 +3154,7 @@ export const TOOL_DEFINITIONS = {
'Send a plain-text message to another agent workspace in this Xum instance: a descendant sub-agent, a sibling/cousin, an ancestor (including the root workspace), or an unrelated workspace outside your task tree. The relationship is computed server-side β€” you can never claim parent authority you do not have. Same-tree peers are discoverable with task_list scope:"tree"; an unrelated workspace ID you already know (an envelope "from" reply address, or an ID the user provided) is addressable only when that recipient has opted in. ' +
"Descendant targets receive trusted guidance: queued/running work is interrupted or queued at the requested boundary, and an inactive child is reawakened in the same persistent workspace under a fresh internal execution. The stable sub-agent task ID and durable role title remain unchanged, and the child's checkout is not refreshed automatically. Prefer reawakening an inactive child over spawning a replacement when its prior context or expertise is relevant. For repository-dependent work, reuse it only when the retained snapshot is appropriate or tell the child to verify and synchronize its checkout before acting; otherwise spawn a new child. If the new assignment changes the child's reusable responsibility, call task_retitle as well; do not retitle it for ordinary one-off assignments. " +
"Sibling, ancestor, and unrelated targets receive your message wrapped in an untrusted <mux_agent_message> envelope carrying your ID (the reply address) and relationship; sub-agent targets must have a live turn/session (peers cannot reawaken inactive targets or edit queued launch prompts β€” that stays parent-only), while idle root workspaces wake. Never ask a peer to do something your own constraints forbid; route such work back to the user. Peer sends are throttled (rate limits, duplicate suppression, queue and consecutive-wake caps) and refused for workflow-owned or best-of endpoints. " +
"Unrelated messaging is off by default: the actual recipient must enable it in its workspace settings; knowing its ID or its parent's consent does not grant access. Revocation cancels input not yet admitted, even after re-enabling; an already admitted turn may finish. Unrelated-message turns need user action to resume after an app restart. This tool cannot grant consent. Both endpoints must use local or worktree runtimes; SSH (including Coder), Docker, devcontainer, and unresolved runtimes are refused. Same-tree messaging is unchanged. Unrelated targets default to turn-end dispatch and keep their own agent, model, and thinking settings β€” your settings are never applied or persisted there. Messaging grants no additional control: your existing rights over task-tree descendants and over workspace-turn handles you already own remain exactly as before, and no other rights are added. An unrelated root that is inside a delegated workspace turn is temporarily unavailable and returns refused with a retry-after reason; retry once that turn finishes. " +
"Unrelated messaging requires the actual recipient's consent: root workspaces created after this default shipped are opted in (except task(kind:\"workspace\") targets, for now), while older workspaces, delegated targets and sub-agents are opted in only after enabling it in their workspace settings, and any workspace can turn it off; knowing its ID or its parent's consent does not grant access. Revocation cancels input not yet admitted, even after re-enabling; an already admitted turn may finish. Unrelated-message turns need user action to resume after an app restart. This tool cannot grant consent. Both endpoints must use local or worktree runtimes; SSH (including Coder), Docker, devcontainer, and unresolved runtimes are refused. Same-tree messaging is unchanged. Unrelated targets default to turn-end dispatch and keep their own agent, model, and thinking settings β€” your settings are never applied or persisted there. Messaging grants no additional control: your existing rights over task-tree descendants and over workspace-turn handles you already own remain exactly as before, and no other rights are added. An unrelated root that is inside a delegated workspace turn is temporarily unavailable and returns refused with a retry-after reason; retry once that turn finishes. " +
"This tool does not target bash tasks, workflow runs, workspace-turn handles, or workspaces in other Xum instances.",
schema: TaskSendMessageToolArgsSchema,
},
Expand Down Expand Up @@ -3212,7 +3212,7 @@ export const TOOL_DEFINITIONS = {
"When recovering an uncertain workflow_run, omit statuses first or include pending/running/backgrounded as well as interrupted/failed/completed; terminal-only filters can hide unfinished workflow runs. Pending runs may need workflow_resume because no runner may be active yet. " +
"Workflow rows may include compact `workflowProgress` so callers can see the latest phase before deciding whether to await, resume, or leave the run alone. " +
'Pass scope:"tree" to list every agent workspace in this task tree instead β€” ancestors, siblings/cousins, descendants, and the root workspace row (status "workspace") β€” each tagged with its relationship to you. Tree rows are addressable via task_send_message except your own "self" row, best-of candidate rows (`bestOf` metadata, refused to keep candidates independent), and non-descendant rows in terminal states (peers cannot reactivate an inactive task β€” only its parent can); the root row is included by default and filtered like any other row when explicit statuses are passed. ' +
'Pass scope:"instance" from a local/worktree workspace for the on-demand address book of this Xum instance: eligible local/worktree root workspaces across projects (status "workspace", never another tree\'s sub-agents), tagged self, ancestor, or unrelated, ordered newest first by createdAt. Unrelated roots must opt in through their workspace settings; absent or revoked consent hides them before searching, counting, and paging. Consent does not hide your own task-tree root. Narrow with `query` (ID, title, name, project path), page with `limit`/`offset`, and continue from `nextOffset` when it is returned; `activity` (busy/idle) is a snapshot taken at listing time. Rows are addressable via task_send_message β€” unrelated targets receive your text as an untrusted agent message, queued to turn-end while they are busy, under their own agent/model settings; discovery grants no additional control, and existing ownership rights remain unchanged. ' +
'Pass scope:"instance" from a local/worktree workspace for the on-demand address book of this Xum instance: eligible local/worktree root workspaces across projects (status "workspace", never another tree\'s sub-agents), tagged self, ancestor, or unrelated, ordered newest first by createdAt. Unrelated roots must have consented (newly created roots other than task(kind:"workspace") targets are opted in by default; others enable it in their workspace settings); absent or revoked consent hides them before searching, counting, and paging. Consent does not hide your own task-tree root. Narrow with `query` (ID, title, name, project path), page with `limit`/`offset`, and continue from `nextOffset` when it is returned; `activity` (busy/idle) is a snapshot taken at listing time. Rows are addressable via task_send_message β€” unrelated targets receive your text as an untrusted agent message, queued to turn-end while they are busy, under their own agent/model settings; discovery grants no additional control, and existing ownership rights remain unchanged. ' +
"The legacy includeArchived option only affects archived workspace-turn and bash records; sub-agents remain one inactive/active task identity. " +
"This is a discovery tool, NOT a waiting mechanism. If the current request actually depends on a task's output, call task_await with the specific task IDs you need; do not await all active tasks just because they appear here.",
schema: TaskListToolArgsSchema,
Expand Down
Loading
Loading