mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 22:44:16 +00:00
docs: document thread-bound subagent sessions and remove plan
This commit is contained in:
@@ -627,6 +627,49 @@ Default slash command settings:
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Thread-bound sessions for subagents">
|
||||
Discord can bind a thread to a session target so follow-up messages in that thread keep routing to the same session (including subagent sessions).
|
||||
|
||||
Commands:
|
||||
|
||||
- `/focus <target>` bind current/new thread to a subagent/session target
|
||||
- `/unfocus` remove current thread binding
|
||||
- `/agents` show active runs and binding state
|
||||
- `/session ttl <duration|off>` inspect/update auto-unfocus TTL for focused bindings
|
||||
|
||||
Config:
|
||||
|
||||
```json5
|
||||
{
|
||||
session: {
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
ttlHours: 24,
|
||||
},
|
||||
},
|
||||
channels: {
|
||||
discord: {
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
ttlHours: 24,
|
||||
spawnSubagentSessions: false, // opt-in
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `session.threadBindings.*` sets global defaults.
|
||||
- `channels.discord.threadBindings.*` overrides Discord behavior.
|
||||
- `spawnSubagentSessions` must be true to auto-create/bind threads for `sessions_spawn({ thread: true })`.
|
||||
- If thread bindings are disabled for an account, `/focus` and related thread binding operations are unavailable.
|
||||
|
||||
See [Sub-agents](/tools/subagents) and [Configuration Reference](/gateway/configuration-reference).
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Reaction notifications">
|
||||
Per-guild reaction notification mode:
|
||||
|
||||
|
||||
@@ -151,7 +151,10 @@ Parameters:
|
||||
- `label?` (optional; used for logs/UI)
|
||||
- `agentId?` (optional; spawn under another agent id if allowed)
|
||||
- `model?` (optional; overrides the sub-agent model; invalid values error)
|
||||
- `thinking?` (optional; overrides thinking level for the sub-agent run)
|
||||
- `runTimeoutSeconds?` (default 0; when set, aborts the sub-agent run after N seconds)
|
||||
- `thread?` (default false; request thread-bound routing for this spawn when supported by the channel/plugin)
|
||||
- `mode?` (`run|session`; defaults to `run`, but defaults to `session` when `thread=true`; `mode="session"` requires `thread=true`)
|
||||
- `cleanup?` (`delete|keep`, default `keep`)
|
||||
|
||||
Allowlist:
|
||||
@@ -168,6 +171,7 @@ Behavior:
|
||||
- Sub-agents default to the full tool set **minus session tools** (configurable via `tools.subagents.tools`).
|
||||
- Sub-agents are not allowed to call `sessions_spawn` (no sub-agent → sub-agent spawning).
|
||||
- Always non-blocking: returns `{ status: "accepted", runId, childSessionKey }` immediately.
|
||||
- With `thread=true`, channel plugins can bind delivery/routing to a thread target (Discord support is controlled by `session.threadBindings.*` and `channels.discord.threadBindings.*`).
|
||||
- After completion, OpenClaw runs a sub-agent **announce step** and posts the result to the requester chat channel.
|
||||
- If the assistant final reply is empty, the latest `toolResult` from sub-agent history is included as `Result`.
|
||||
- Reply exactly `ANNOUNCE_SKIP` during the announce step to stay silent.
|
||||
|
||||
@@ -1,338 +0,0 @@
|
||||
---
|
||||
summary: "Discord thread bound subagent sessions with plugin lifecycle hooks, routing, and config kill switches"
|
||||
owner: "onutc"
|
||||
status: "implemented"
|
||||
last_updated: "2026-02-21"
|
||||
title: "Thread Bound Subagents"
|
||||
---
|
||||
|
||||
# Thread Bound Subagents
|
||||
|
||||
## Overview
|
||||
|
||||
This feature lets users interact with spawned subagents directly inside Discord threads.
|
||||
|
||||
Instead of only waiting for a completion summary in the parent session, users can move into a dedicated thread that routes messages to the spawned subagent session. Replies are sent in-thread with a thread bound persona.
|
||||
|
||||
The implementation is split between channel agnostic core lifecycle hooks and Discord specific extension behavior.
|
||||
|
||||
## Goals
|
||||
|
||||
- Allow direct thread conversation with a spawned subagent session.
|
||||
- Keep default subagent orchestration channel agnostic.
|
||||
- Support both automatic thread creation on spawn and manual focus controls.
|
||||
- Provide predictable cleanup on completion, kill, timeout, and thread lifecycle changes.
|
||||
- Keep behavior configurable with global defaults plus channel and account overrides.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- New ACP protocol features.
|
||||
- Non Discord thread binding implementations in this document.
|
||||
- New bot accounts or app level Discord identity changes.
|
||||
|
||||
## What shipped
|
||||
|
||||
- `sessions_spawn` supports `thread: true` and `mode: "run" | "session"`.
|
||||
- Spawn flow supports persistent thread bound sessions.
|
||||
- Discord thread binding manager supports bind, unbind, TTL sweep, and persistence.
|
||||
- Plugin hook lifecycle for subagents:
|
||||
- `subagent_spawning`
|
||||
- `subagent_spawned`
|
||||
- `subagent_delivery_target`
|
||||
- `subagent_ended`
|
||||
- Discord extension implements thread auto bind, delivery target override, and unbind on end.
|
||||
- Text commands for manual control:
|
||||
- `/focus`
|
||||
- `/unfocus`
|
||||
- `/agents`
|
||||
- `/session ttl`
|
||||
- Global and Discord scoped enablement and TTL controls, including a global kill switch.
|
||||
|
||||
## Core concepts
|
||||
|
||||
### Spawn modes
|
||||
|
||||
- `mode: "run"`
|
||||
- one task lifecycle
|
||||
- completion announcement flow
|
||||
- `mode: "session"`
|
||||
- persistent thread bound session
|
||||
- supports follow up user messages in thread
|
||||
|
||||
Default mode behavior:
|
||||
|
||||
- if `thread: true` and mode omitted, mode defaults to `"session"`
|
||||
- otherwise mode defaults to `"run"`
|
||||
|
||||
Constraint:
|
||||
|
||||
- `mode: "session"` requires `thread: true`
|
||||
|
||||
### Thread binding target model
|
||||
|
||||
Bindings are generic targets, not only subagents.
|
||||
|
||||
- `targetKind: "subagent" | "acp"`
|
||||
- `targetSessionKey: string`
|
||||
|
||||
This allows the same routing primitive to support ACP/session bindings as well.
|
||||
|
||||
### Thread binding manager
|
||||
|
||||
The manager is responsible for:
|
||||
|
||||
- binding or creating threads for a session target
|
||||
- unbinding by thread or by target session
|
||||
- managing webhook reuse and recent unbound webhook echo suppression
|
||||
- TTL based unbind and stale thread cleanup
|
||||
- persistence load and save
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core and extension boundary
|
||||
|
||||
Core (`src/agents/*`) does not directly depend on Discord routing internals.
|
||||
|
||||
Core emits lifecycle intent through plugin hooks.
|
||||
|
||||
Discord extension (`extensions/discord/src/subagent-hooks.ts`) implements Discord specific behavior:
|
||||
|
||||
- pre spawn thread bind preparation
|
||||
- completion delivery target override to bound thread
|
||||
- unbind on subagent end
|
||||
|
||||
### Plugin hook flow
|
||||
|
||||
1. `subagent_spawning`
|
||||
- before run starts
|
||||
- can block spawn with `status: "error"`
|
||||
- used to prepare thread binding when `thread: true`
|
||||
2. `subagent_spawned`
|
||||
- post run registration event
|
||||
3. `subagent_delivery_target`
|
||||
- completion routing override hook
|
||||
- can redirect completion delivery to bound Discord thread origin
|
||||
4. `subagent_ended`
|
||||
- cleanup and unbind signal
|
||||
|
||||
### Account ID normalization contract
|
||||
|
||||
Thread binding and routing state must use one canonical account id abstraction.
|
||||
|
||||
Specification:
|
||||
|
||||
- Introduce a shared account id module (proposed: `src/routing/account-id.ts`) and stop defining local normalizers.
|
||||
- Expose two explicit helpers:
|
||||
- `normalizeAccountId(value): string`
|
||||
- returns canonical, defaulted id (current default is `default`)
|
||||
- use for map keys, manager registration and lookup, persistence keys, routing keys
|
||||
- `normalizeOptionalAccountId(value): string | undefined`
|
||||
- returns canonical id when present, `undefined` when absent
|
||||
- use for inbound optional context fields and merge logic
|
||||
- Do not implement ad hoc account normalization in feature modules.
|
||||
- This includes `trim`, `toLowerCase`, or defaulting logic in local helper functions.
|
||||
- Any map keyed by account id must only accept canonical ids from shared helpers.
|
||||
- Hook payloads and delivery context should carry raw optional account ids, and normalize at module boundaries only.
|
||||
|
||||
Migration guardrails:
|
||||
|
||||
- Replace duplicate normalizers in routing, reply payload, command context, and provider helpers with shared helpers.
|
||||
- Add contract tests that assert identical normalization behavior across:
|
||||
- route resolution
|
||||
- thread binding manager lookup
|
||||
- reply delivery target filtering
|
||||
- command run context merge
|
||||
|
||||
### Persistence and state
|
||||
|
||||
Binding state path:
|
||||
|
||||
- `${stateDir}/discord/thread-bindings.json`
|
||||
|
||||
Record shape contains:
|
||||
|
||||
- account, channel, thread
|
||||
- target kind and target session key
|
||||
- agent label metadata
|
||||
- webhook id/token
|
||||
- boundBy, boundAt, expiresAt
|
||||
|
||||
State is stored on `globalThis` to keep one shared registry across ESM and Jiti loader paths.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Effective precedence
|
||||
|
||||
For Discord thread binding options, account override wins, then channel, then global session default, then built in fallback.
|
||||
|
||||
- account: `channels.discord.accounts.<id>.threadBindings.<key>`
|
||||
- channel: `channels.discord.threadBindings.<key>`
|
||||
- global: `session.threadBindings.<key>`
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Scope | Default | Notes |
|
||||
| ------------------------------------------------------- | --------------- | --------------- | ----------------------------------------- |
|
||||
| `session.threadBindings.enabled` | global | `true` | master default kill switch |
|
||||
| `session.threadBindings.ttlHours` | global | `24` | default auto unfocus TTL |
|
||||
| `channels.discord.threadBindings.enabled` | channel/account | inherits global | Discord override kill switch |
|
||||
| `channels.discord.threadBindings.ttlHours` | channel/account | inherits global | Discord TTL override |
|
||||
| `channels.discord.threadBindings.spawnSubagentSessions` | channel/account | `false` | opt in for `thread: true` spawn auto bind |
|
||||
|
||||
### Runtime effect of enable switch
|
||||
|
||||
When effective `enabled` is false for a Discord account:
|
||||
|
||||
- provider creates a noop thread binding manager for runtime wiring
|
||||
- no real manager is registered for lookup by account id
|
||||
- inbound bound thread routing is effectively disabled
|
||||
- completion routing overrides do not resolve bound thread origins
|
||||
- `/focus`, `/unfocus`, and thread binding specific operations report unavailable
|
||||
- `thread: true` spawn path returns actionable error from Discord hook layer
|
||||
|
||||
## Flow and behavior
|
||||
|
||||
### Spawn with `thread: true`
|
||||
|
||||
1. Spawn validates mode and permissions.
|
||||
2. `subagent_spawning` hook runs.
|
||||
3. Discord extension checks effective flags:
|
||||
- thread bindings enabled
|
||||
- `spawnSubagentSessions` enabled
|
||||
4. Extension attempts auto bind and thread creation.
|
||||
5. If bind fails:
|
||||
- spawn returns error
|
||||
- provisional child session is deleted
|
||||
6. If bind succeeds:
|
||||
- child run starts
|
||||
- run is registered with spawn mode
|
||||
|
||||
### Manual focus and unfocus
|
||||
|
||||
- `/focus <target>`
|
||||
- Discord only
|
||||
- resolves subagent or session target
|
||||
- binds current or created thread to target session
|
||||
- `/unfocus`
|
||||
- Discord thread only
|
||||
- unbinds current thread
|
||||
|
||||
### Inbound routing
|
||||
|
||||
- Discord preflight checks current thread id against thread binding manager.
|
||||
- If bound, effective session routing uses bound target session key.
|
||||
- If not bound, normal routing path is used.
|
||||
|
||||
### Outbound routing
|
||||
|
||||
- Reply delivery checks whether current session has thread bindings.
|
||||
- Bound sessions deliver to thread via webhook aware path.
|
||||
- Unbound sessions use normal bot delivery.
|
||||
|
||||
### Completion routing
|
||||
|
||||
- Core completion flow calls `subagent_delivery_target`.
|
||||
- Discord extension returns bound thread origin when it can resolve one.
|
||||
- Core merges hook origin with requester origin and delivers completion.
|
||||
|
||||
### Cleanup
|
||||
|
||||
Cleanup occurs on:
|
||||
|
||||
- completion
|
||||
- error or timeout completion path
|
||||
- kill and terminate paths
|
||||
- TTL expiration
|
||||
- archived or deleted thread probes
|
||||
- manual `/unfocus`
|
||||
|
||||
Cleanup behavior includes unbind and optional farewell messaging.
|
||||
|
||||
## Commands and user UX
|
||||
|
||||
| Command | Purpose |
|
||||
| ---------------------------------------------------------- | -------------------------------------------------------------------- | ------------------------------------- | --------------- | ------------------------------------------- |
|
||||
| `/subagents spawn <agentId> <task> [--model] [--thinking]` | spawn subagent; may be thread bound when `thread: true` path is used |
|
||||
| `/focus <subagent-label | session-key | session-id | session-label>` | manually bind thread to subagent or session |
|
||||
| `/unfocus` | remove binding from current thread |
|
||||
| `/agents` | list active agents and binding state |
|
||||
| `/session ttl <duration | off>` | update TTL for focused thread binding |
|
||||
|
||||
Notes:
|
||||
|
||||
- `/session ttl` is currently Discord thread focused behavior.
|
||||
- Thread intro and farewell text are generated by thread binding message helpers.
|
||||
|
||||
## Failure handling and safety
|
||||
|
||||
- Spawn returns explicit errors when thread binding cannot be prepared.
|
||||
- Spawn failure after provisional bind attempts best effort unbind and session delete.
|
||||
- Completion logic prevents duplicate ended hook emission.
|
||||
- Retry and expiry guards prevent infinite completion announce retry loops.
|
||||
- Webhook echo suppression avoids unbound webhook messages being reprocessed as inbound turns.
|
||||
|
||||
## Module map
|
||||
|
||||
### Core orchestration
|
||||
|
||||
- `src/agents/subagent-spawn.ts`
|
||||
- `src/agents/subagent-announce.ts`
|
||||
- `src/agents/subagent-registry.ts`
|
||||
- `src/agents/subagent-registry-cleanup.ts`
|
||||
- `src/agents/subagent-registry-completion.ts`
|
||||
|
||||
### Discord runtime
|
||||
|
||||
- `src/discord/monitor/provider.ts`
|
||||
- `src/discord/monitor/thread-bindings.manager.ts`
|
||||
- `src/discord/monitor/thread-bindings.state.ts`
|
||||
- `src/discord/monitor/thread-bindings.lifecycle.ts`
|
||||
- `src/discord/monitor/thread-bindings.messages.ts`
|
||||
- `src/discord/monitor/message-handler.preflight.ts`
|
||||
- `src/discord/monitor/message-handler.process.ts`
|
||||
- `src/discord/monitor/reply-delivery.ts`
|
||||
|
||||
### Plugin hooks and extension
|
||||
|
||||
- `src/plugins/types.ts`
|
||||
- `src/plugins/hooks.ts`
|
||||
- `extensions/discord/src/subagent-hooks.ts`
|
||||
|
||||
### Config and schema
|
||||
|
||||
- `src/config/types.base.ts`
|
||||
- `src/config/types.discord.ts`
|
||||
- `src/config/zod-schema.session.ts`
|
||||
- `src/config/zod-schema.providers-core.ts`
|
||||
- `src/config/schema.help.ts`
|
||||
- `src/config/schema.labels.ts`
|
||||
|
||||
## Test coverage highlights
|
||||
|
||||
- `extensions/discord/src/subagent-hooks.test.ts`
|
||||
- `src/discord/monitor/thread-bindings.ttl.test.ts`
|
||||
- `src/discord/monitor/thread-bindings.shared-state.test.ts`
|
||||
- `src/discord/monitor/reply-delivery.test.ts`
|
||||
- `src/discord/monitor/message-handler.preflight.test.ts`
|
||||
- `src/discord/monitor/message-handler.process.test.ts`
|
||||
- `src/auto-reply/reply/commands-subagents-focus.test.ts`
|
||||
- `src/auto-reply/reply/commands-session-ttl.test.ts`
|
||||
- `src/agents/subagent-registry.steer-restart.test.ts`
|
||||
- `src/agents/subagent-registry-completion.test.ts`
|
||||
|
||||
## Operational summary
|
||||
|
||||
- Use `session.threadBindings.enabled` as the global kill switch default.
|
||||
- Use `channels.discord.threadBindings.enabled` and account overrides for selective enablement.
|
||||
- Keep `spawnSubagentSessions` opt in for thread auto spawn behavior.
|
||||
- Use TTL settings for automatic unfocus policy control.
|
||||
|
||||
This model keeps subagent lifecycle orchestration generic while giving Discord a full thread bound interaction path.
|
||||
|
||||
## Related plan
|
||||
|
||||
For channel agnostic SessionBinding architecture and scoped iteration planning, see:
|
||||
|
||||
- `docs/experiments/plans/session-binding-channel-agnostic.md`
|
||||
|
||||
ACP remains a next step in that plan and is intentionally not implemented in this shipped Discord thread-bound flow.
|
||||
@@ -235,6 +235,11 @@ WhatsApp runs through the gateway's web channel (Baileys Web). It starts automat
|
||||
accentColor: "#5865F2",
|
||||
},
|
||||
},
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
ttlHours: 24,
|
||||
spawnSubagentSessions: false, // opt-in for sessions_spawn({ thread: true })
|
||||
},
|
||||
voice: {
|
||||
enabled: true,
|
||||
autoJoin: [
|
||||
@@ -264,6 +269,10 @@ WhatsApp runs through the gateway's web channel (Baileys Web). It starts automat
|
||||
- Guild slugs are lowercase with spaces replaced by `-`; channel keys use the slugged name (no `#`). Prefer guild IDs.
|
||||
- Bot-authored messages are ignored by default. `allowBots: true` enables them (own messages still filtered).
|
||||
- `maxLinesPerMessage` (default 17) splits tall messages even when under 2000 chars.
|
||||
- `channels.discord.threadBindings` controls Discord thread-bound routing:
|
||||
- `enabled`: Discord override for thread-bound session features (`/focus`, `/unfocus`, `/agents`, `/session ttl`, and bound delivery/routing)
|
||||
- `ttlHours`: Discord override for auto-unfocus TTL (`0` disables)
|
||||
- `spawnSubagentSessions`: opt-in switch for `sessions_spawn({ thread: true })` auto thread creation/binding
|
||||
- `channels.discord.ui.components.accentColor` sets the accent color for Discord components v2 containers.
|
||||
- `channels.discord.voice` enables Discord voice channel conversations and optional auto-join + TTS overrides.
|
||||
- `channels.discord.streaming` is the canonical stream mode key. Legacy `streamMode` and boolean `streaming` values are auto-migrated.
|
||||
@@ -1222,6 +1231,10 @@ See [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) for preceden
|
||||
maxEntries: 500,
|
||||
rotateBytes: "10mb",
|
||||
},
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
ttlHours: 24, // default auto-unfocus TTL for thread-bound sessions (0 disables)
|
||||
},
|
||||
mainKey: "main", // legacy (runtime always uses "main")
|
||||
agentToAgent: { maxPingPongTurns: 5 },
|
||||
sendPolicy: {
|
||||
@@ -1245,6 +1258,9 @@ See [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) for preceden
|
||||
- **`mainKey`**: legacy field. Runtime now always uses `"main"` for the main direct-chat bucket.
|
||||
- **`sendPolicy`**: match by `channel`, `chatType` (`direct|group|channel`, with legacy `dm` alias), `keyPrefix`, or `rawKeyPrefix`. First deny wins.
|
||||
- **`maintenance`**: `warn` warns the active session on eviction; `enforce` applies pruning and rotation.
|
||||
- **`threadBindings`**: global defaults for thread-bound session features.
|
||||
- `enabled`: master default switch (providers can override; Discord uses `channels.discord.threadBindings.enabled`)
|
||||
- `ttlHours`: default auto-unfocus TTL in hours (`0` disables; providers can override)
|
||||
|
||||
</Accordion>
|
||||
|
||||
|
||||
@@ -182,6 +182,10 @@ When validation fails:
|
||||
{
|
||||
session: {
|
||||
dmScope: "per-channel-peer", // recommended for multi-user
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
ttlHours: 24,
|
||||
},
|
||||
reset: {
|
||||
mode: "daily",
|
||||
atHour: 4,
|
||||
@@ -192,6 +196,7 @@ When validation fails:
|
||||
```
|
||||
|
||||
- `dmScope`: `main` (shared) | `per-peer` | `per-channel-peer` | `per-account-channel-peer`
|
||||
- `threadBindings`: global defaults for thread-bound session routing (Discord supports `/focus`, `/unfocus`, `/agents`, and `/session ttl`).
|
||||
- See [Session Management](/concepts/session) for scoping, identity links, and send policy.
|
||||
- See [full reference](/gateway/configuration-reference#session) for all fields.
|
||||
|
||||
|
||||
@@ -1038,6 +1038,26 @@ cheaper model for sub-agents via `agents.defaults.subagents.model`.
|
||||
|
||||
Docs: [Sub-agents](/tools/subagents).
|
||||
|
||||
### How do thread-bound subagent sessions work on Discord
|
||||
|
||||
Use thread bindings. You can bind a Discord thread to a subagent or session target so follow-up messages in that thread stay on that bound session.
|
||||
|
||||
Basic flow:
|
||||
|
||||
- Spawn with `sessions_spawn` using `thread: true` (and optionally `mode: "session"` for persistent follow-up).
|
||||
- Or manually bind with `/focus <target>`.
|
||||
- Use `/agents` to inspect binding state.
|
||||
- Use `/session ttl <duration|off>` to control auto-unfocus.
|
||||
- Use `/unfocus` to detach the thread.
|
||||
|
||||
Required config:
|
||||
|
||||
- Global defaults: `session.threadBindings.enabled`, `session.threadBindings.ttlHours`.
|
||||
- Discord overrides: `channels.discord.threadBindings.enabled`, `channels.discord.threadBindings.ttlHours`.
|
||||
- Auto-bind on spawn: set `channels.discord.threadBindings.spawnSubagentSessions: true`.
|
||||
|
||||
Docs: [Sub-agents](/tools/subagents), [Discord](/channels/discord), [Configuration Reference](/gateway/configuration-reference), [Slash commands](/tools/slash-commands).
|
||||
|
||||
### Cron or reminders do not fire What should I check
|
||||
|
||||
Cron runs inside the Gateway process. If the Gateway is not running continuously,
|
||||
|
||||
@@ -464,7 +464,7 @@ Core parameters:
|
||||
- `sessions_list`: `kinds?`, `limit?`, `activeMinutes?`, `messageLimit?` (0 = none)
|
||||
- `sessions_history`: `sessionKey` (or `sessionId`), `limit?`, `includeTools?`
|
||||
- `sessions_send`: `sessionKey` (or `sessionId`), `message`, `timeoutSeconds?` (0 = fire-and-forget)
|
||||
- `sessions_spawn`: `task`, `label?`, `agentId?`, `model?`, `runTimeoutSeconds?`, `cleanup?`
|
||||
- `sessions_spawn`: `task`, `label?`, `agentId?`, `model?`, `thinking?`, `runTimeoutSeconds?`, `thread?`, `mode?`, `cleanup?`
|
||||
- `session_status`: `sessionKey?` (default current; accepts `sessionId`), `model?` (`default` clears override)
|
||||
|
||||
Notes:
|
||||
@@ -475,6 +475,10 @@ Notes:
|
||||
- `sessions_send` waits for final completion when `timeoutSeconds > 0`.
|
||||
- Delivery/announce happens after completion and is best-effort; `status: "ok"` confirms the agent run finished, not that the announce was delivered.
|
||||
- `sessions_spawn` starts a sub-agent run and posts an announce reply back to the requester chat.
|
||||
- Supports one-shot mode (`mode: "run"`) and persistent thread-bound mode (`mode: "session"` with `thread: true`).
|
||||
- If `thread: true` and `mode` is omitted, mode defaults to `session`.
|
||||
- `mode: "session"` requires `thread: true`.
|
||||
- Discord thread-bound flows depend on `session.threadBindings.*` and `channels.discord.threadBindings.*`.
|
||||
- Reply format includes `Status`, `Result`, and compact stats.
|
||||
- `Result` is the assistant completion text; if missing, the latest `toolResult` is used as fallback.
|
||||
- Manual completion-mode spawns send directly first, with queue fallback and retry on transient failures (`status: "ok"` means run finished, not that announce delivered).
|
||||
|
||||
@@ -124,6 +124,7 @@ Notes:
|
||||
- `/usage` controls the per-response usage footer; `/usage cost` prints a local cost summary from OpenClaw session logs.
|
||||
- `/restart` is enabled by default; set `commands.restart: false` to disable it.
|
||||
- Discord-only native command: `/vc join|leave|status` controls voice channels (requires `channels.discord.voice` and native commands; not available as text).
|
||||
- Discord thread-binding commands (`/focus`, `/unfocus`, `/agents`, `/session ttl`) require effective thread bindings to be enabled (`session.threadBindings.enabled` and/or `channels.discord.threadBindings.enabled`).
|
||||
- `/verbose` is meant for debugging and extra visibility; keep it **off** in normal use.
|
||||
- `/reasoning` (and `/verbose`) are risky in group settings: they may reveal internal reasoning or tool output you did not intend to expose. Prefer leaving them off, especially in group chats.
|
||||
- **Fast path:** command-only messages from allowlisted senders are handled immediately (bypass queue + model).
|
||||
|
||||
@@ -3,6 +3,7 @@ summary: "Sub-agents: spawning isolated agent runs that announce results back to
|
||||
read_when:
|
||||
- You want background/parallel work via the agent
|
||||
- You are changing sessions_spawn or sub-agent tool policy
|
||||
- You are implementing or troubleshooting thread-bound subagent sessions
|
||||
title: "Sub-Agents"
|
||||
---
|
||||
|
||||
@@ -22,6 +23,13 @@ Use `/subagents` to inspect or control sub-agent runs for the **current session*
|
||||
- `/subagents steer <id|#> <message>`
|
||||
- `/subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]`
|
||||
|
||||
Discord thread binding controls:
|
||||
|
||||
- `/focus <subagent-label|session-key|session-id|session-label>`
|
||||
- `/unfocus`
|
||||
- `/agents`
|
||||
- `/session ttl <duration|off>`
|
||||
|
||||
`/subagents info` shows run metadata (status, timestamps, session id, transcript path, cleanup).
|
||||
|
||||
### Spawn behavior
|
||||
@@ -40,6 +48,7 @@ Use `/subagents` to inspect or control sub-agent runs for the **current session*
|
||||
- compact runtime/token stats
|
||||
- `--model` and `--thinking` override defaults for that specific run.
|
||||
- Use `info`/`log` to inspect details and output after completion.
|
||||
- `/subagents spawn` is one-shot mode (`mode: "run"`). For persistent thread-bound sessions, use `sessions_spawn` with `thread: true` and `mode: "session"`.
|
||||
|
||||
Primary goals:
|
||||
|
||||
@@ -69,8 +78,40 @@ Tool params:
|
||||
- `model?` (optional; overrides the sub-agent model; invalid values are skipped and the sub-agent runs on the default model with a warning in the tool result)
|
||||
- `thinking?` (optional; overrides thinking level for the sub-agent run)
|
||||
- `runTimeoutSeconds?` (default `0`; when set, the sub-agent run is aborted after N seconds)
|
||||
- `thread?` (default `false`; when `true`, requests channel thread binding for this sub-agent session)
|
||||
- `mode?` (`run|session`)
|
||||
- default is `run`
|
||||
- if `thread: true` and `mode` omitted, default becomes `session`
|
||||
- `mode: "session"` requires `thread: true`
|
||||
- `cleanup?` (`delete|keep`, default `keep`)
|
||||
|
||||
## Discord thread-bound sessions
|
||||
|
||||
When thread bindings are enabled, a sub-agent can stay bound to a Discord thread so follow-up user messages in that thread keep routing to the same sub-agent session.
|
||||
|
||||
Quick flow:
|
||||
|
||||
1. Spawn with `sessions_spawn` using `thread: true` (and optionally `mode: "session"`).
|
||||
2. OpenClaw creates or binds a Discord thread to that session target.
|
||||
3. Replies and follow-up messages in that thread route to the bound session.
|
||||
4. Use `/session ttl` to inspect/update auto-unfocus TTL.
|
||||
5. Use `/unfocus` to detach manually.
|
||||
|
||||
Manual controls:
|
||||
|
||||
- `/focus <target>` binds the current thread (or creates one) to a sub-agent/session target.
|
||||
- `/unfocus` removes the binding for the current Discord thread.
|
||||
- `/agents` lists active runs and binding state (`thread:<id>` or `unbound`).
|
||||
- `/session ttl` only works for focused Discord threads.
|
||||
|
||||
Config switches:
|
||||
|
||||
- Global default: `session.threadBindings.enabled`, `session.threadBindings.ttlHours`
|
||||
- Discord override: `channels.discord.threadBindings.enabled`, `channels.discord.threadBindings.ttlHours`
|
||||
- Spawn auto-bind opt-in: `channels.discord.threadBindings.spawnSubagentSessions`
|
||||
|
||||
See [Discord](/channels/discord), [Configuration Reference](/gateway/configuration-reference), and [Slash commands](/tools/slash-commands).
|
||||
|
||||
Allowlist:
|
||||
|
||||
- `agents.list[].subagents.allowAgents`: list of agent ids that can be targeted via `agentId` (`["*"]` to allow any). Default: only the requester agent.
|
||||
|
||||
Reference in New Issue
Block a user