mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
feat: thread-bound subagents on Discord (#21805)
* docs: thread-bound subagents plan * docs: add exact thread-bound subagent implementation touchpoints * Docs: prioritize auto thread-bound subagent flow * Docs: add ACP harness thread-binding extensions * Discord: add thread-bound session routing and auto-bind spawn flow * Subagents: add focus commands and ACP/session binding lifecycle hooks * Tests: cover thread bindings, focus commands, and ACP unbind hooks * Docs: add plugin-hook appendix for thread-bound subagents * Plugins: add subagent lifecycle hook events * Core: emit subagent lifecycle hooks and decouple Discord bindings * Discord: handle subagent bind lifecycle via plugin hooks * Subagents: unify completion finalizer and split registry modules * Add subagent lifecycle events module * Hooks: fix subagent ended context key * Discord: share thread bindings across ESM and Jiti * Subagents: add persistent sessions_spawn mode for thread-bound sessions * Subagents: clarify thread intro and persistent completion copy * test(subagents): stabilize sessions_spawn lifecycle cleanup assertions * Discord: add thread-bound session TTL with auto-unfocus * Subagents: fail session spawns when thread bind fails * Subagents: cover thread session failure cleanup paths * Session: add thread binding TTL config and /session ttl controls * Tests: align discord reaction expectations * Agent: persist sessionFile for keyed subagent sessions * Discord: normalize imports after conflict resolution * Sessions: centralize sessionFile resolve/persist helper * Discord: harden thread-bound subagent session routing * Rebase: resolve upstream/main conflicts * Subagents: move thread binding into hooks and split bindings modules * Docs: add channel-agnostic subagent routing hook plan * Agents: decouple subagent routing from Discord * Discord: refactor thread-bound subagent flows * Subagents: prevent duplicate end hooks and orphaned failed sessions * Refactor: split subagent command and provider phases * Subagents: honor hook delivery target overrides * Discord: add thread binding kill switches and refresh plan doc * Discord: fix thread bind channel resolution * Routing: centralize account id normalization * Discord: clean up thread bindings on startup failures * Discord: add startup cleanup regression tests * Docs: add long-term thread-bound subagent architecture * Docs: split session binding plan and dedupe thread-bound doc * Subagents: add channel-agnostic session binding routing * Subagents: stabilize announce completion routing tests * Subagents: cover multi-bound completion routing * Subagents: suppress lifecycle hooks on failed thread bind * tests: fix discord provider mock typing regressions * docs/protocol: sync slash command aliases and delete param models * fix: add changelog entry for Discord thread-bound subagents (#21805) (thanks @onutc) --------- Co-authored-by: Shadow <hi@shadowing.dev>
This commit is contained in:
223
docs/experiments/plans/session-binding-channel-agnostic.md
Normal file
223
docs/experiments/plans/session-binding-channel-agnostic.md
Normal file
@@ -0,0 +1,223 @@
|
||||
---
|
||||
summary: "Channel agnostic session binding architecture and iteration 1 delivery scope"
|
||||
owner: "onutc"
|
||||
status: "in-progress"
|
||||
last_updated: "2026-02-21"
|
||||
title: "Session Binding Channel Agnostic Plan"
|
||||
---
|
||||
|
||||
# Session Binding Channel Agnostic Plan
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines the long term channel agnostic session binding model and the concrete scope for the next implementation iteration.
|
||||
|
||||
Goal:
|
||||
|
||||
- make subagent bound session routing a core capability
|
||||
- keep channel specific behavior in adapters
|
||||
- avoid regressions in normal Discord behavior
|
||||
|
||||
## Why this exists
|
||||
|
||||
Current behavior mixes:
|
||||
|
||||
- completion content policy
|
||||
- destination routing policy
|
||||
- Discord specific details
|
||||
|
||||
This caused edge cases such as:
|
||||
|
||||
- duplicate main and thread delivery under concurrent runs
|
||||
- stale token usage on reused binding managers
|
||||
- missing activity accounting for webhook sends
|
||||
|
||||
## Iteration 1 scope
|
||||
|
||||
This iteration is intentionally limited.
|
||||
|
||||
### 1. Add channel agnostic core interfaces
|
||||
|
||||
Add core types and service interfaces for bindings and routing.
|
||||
|
||||
Proposed core types:
|
||||
|
||||
```ts
|
||||
export type BindingTargetKind = "subagent" | "session";
|
||||
export type BindingStatus = "active" | "ending" | "ended";
|
||||
|
||||
export type ConversationRef = {
|
||||
channel: string;
|
||||
accountId: string;
|
||||
conversationId: string;
|
||||
parentConversationId?: string;
|
||||
};
|
||||
|
||||
export type SessionBindingRecord = {
|
||||
bindingId: string;
|
||||
targetSessionKey: string;
|
||||
targetKind: BindingTargetKind;
|
||||
conversation: ConversationRef;
|
||||
status: BindingStatus;
|
||||
boundAt: number;
|
||||
expiresAt?: number;
|
||||
metadata?: Record<string, unknown>;
|
||||
};
|
||||
```
|
||||
|
||||
Core service contract:
|
||||
|
||||
```ts
|
||||
export interface SessionBindingService {
|
||||
bind(input: {
|
||||
targetSessionKey: string;
|
||||
targetKind: BindingTargetKind;
|
||||
conversation: ConversationRef;
|
||||
metadata?: Record<string, unknown>;
|
||||
ttlMs?: number;
|
||||
}): Promise<SessionBindingRecord>;
|
||||
|
||||
listBySession(targetSessionKey: string): SessionBindingRecord[];
|
||||
resolveByConversation(ref: ConversationRef): SessionBindingRecord | null;
|
||||
touch(bindingId: string, at?: number): void;
|
||||
unbind(input: {
|
||||
bindingId?: string;
|
||||
targetSessionKey?: string;
|
||||
reason: string;
|
||||
}): Promise<SessionBindingRecord[]>;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Add one core delivery router for subagent completions
|
||||
|
||||
Add a single destination resolution path for completion events.
|
||||
|
||||
Router contract:
|
||||
|
||||
```ts
|
||||
export interface BoundDeliveryRouter {
|
||||
resolveDestination(input: {
|
||||
eventKind: "task_completion";
|
||||
targetSessionKey: string;
|
||||
requester?: ConversationRef;
|
||||
failClosed: boolean;
|
||||
}): {
|
||||
binding: SessionBindingRecord | null;
|
||||
mode: "bound" | "fallback";
|
||||
reason: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
For this iteration:
|
||||
|
||||
- only `task_completion` is routed through this new path
|
||||
- existing paths for other event kinds remain as-is
|
||||
|
||||
### 3. Keep Discord as adapter
|
||||
|
||||
Discord remains the first adapter implementation.
|
||||
|
||||
Adapter responsibilities:
|
||||
|
||||
- create/reuse thread conversations
|
||||
- send bound messages via webhook or channel send
|
||||
- validate thread state (archived/deleted)
|
||||
- map adapter metadata (webhook identity, thread ids)
|
||||
|
||||
### 4. Fix currently known correctness issues
|
||||
|
||||
Required in this iteration:
|
||||
|
||||
- refresh token usage when reusing existing thread binding manager
|
||||
- record outbound activity for webhook based Discord sends
|
||||
- stop implicit main channel fallback when a bound thread destination is selected for session mode completion
|
||||
|
||||
### 5. Preserve current runtime safety defaults
|
||||
|
||||
No behavior change for users with thread bound spawn disabled.
|
||||
|
||||
Defaults stay:
|
||||
|
||||
- `channels.discord.threadBindings.spawnSubagentSessions = false`
|
||||
|
||||
Result:
|
||||
|
||||
- normal Discord users stay on current behavior
|
||||
- new core path affects only bound session completion routing where enabled
|
||||
|
||||
## Not in iteration 1
|
||||
|
||||
Explicitly deferred:
|
||||
|
||||
- ACP binding targets (`targetKind: "acp"`)
|
||||
- new channel adapters beyond Discord
|
||||
- global replacement of all delivery paths (`spawn_ack`, future `subagent_message`)
|
||||
- protocol level changes
|
||||
- store migration/versioning redesign for all binding persistence
|
||||
|
||||
Notes on ACP:
|
||||
|
||||
- interface design keeps room for ACP
|
||||
- ACP implementation is not started in this iteration
|
||||
|
||||
## Routing invariants
|
||||
|
||||
These invariants are mandatory for iteration 1.
|
||||
|
||||
- destination selection and content generation are separate steps
|
||||
- if session mode completion resolves to an active bound destination, delivery must target that destination
|
||||
- no hidden reroute from bound destination to main channel
|
||||
- fallback behavior must be explicit and observable
|
||||
|
||||
## Compatibility and rollout
|
||||
|
||||
Compatibility target:
|
||||
|
||||
- no regression for users with thread bound spawning off
|
||||
- no change to non-Discord channels in this iteration
|
||||
|
||||
Rollout:
|
||||
|
||||
1. Land interfaces and router behind current feature gates.
|
||||
2. Route Discord completion mode bound deliveries through router.
|
||||
3. Keep legacy path for non-bound flows.
|
||||
4. Verify with targeted tests and canary runtime logs.
|
||||
|
||||
## Tests required in iteration 1
|
||||
|
||||
Unit and integration coverage required:
|
||||
|
||||
- manager token rotation uses latest token after manager reuse
|
||||
- webhook sends update channel activity timestamps
|
||||
- two active bound sessions in same requester channel do not duplicate to main channel
|
||||
- completion for bound session mode run resolves to thread destination only
|
||||
- disabled spawn flag keeps legacy behavior unchanged
|
||||
|
||||
## Proposed implementation files
|
||||
|
||||
Core:
|
||||
|
||||
- `src/infra/outbound/session-binding-service.ts` (new)
|
||||
- `src/infra/outbound/bound-delivery-router.ts` (new)
|
||||
- `src/agents/subagent-announce.ts` (completion destination resolution integration)
|
||||
|
||||
Discord adapter and runtime:
|
||||
|
||||
- `src/discord/monitor/thread-bindings.manager.ts`
|
||||
- `src/discord/monitor/reply-delivery.ts`
|
||||
- `src/discord/send.outbound.ts`
|
||||
|
||||
Tests:
|
||||
|
||||
- `src/discord/monitor/provider*.test.ts`
|
||||
- `src/discord/monitor/reply-delivery.test.ts`
|
||||
- `src/agents/subagent-announce.format.e2e.test.ts`
|
||||
|
||||
## Done criteria for iteration 1
|
||||
|
||||
- core interfaces exist and are wired for completion routing
|
||||
- correctness fixes above are merged with tests
|
||||
- no main and thread duplicate completion delivery in session mode bound runs
|
||||
- no behavior change for disabled bound spawn deployments
|
||||
- ACP remains explicitly deferred
|
||||
338
docs/experiments/plans/thread-bound-subagents.md
Normal file
338
docs/experiments/plans/thread-bound-subagents.md
Normal file
@@ -0,0 +1,338 @@
|
||||
---
|
||||
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.
|
||||
Reference in New Issue
Block a user