Skip to content

Commit 6a705a3

Browse files
dutifulbobosolmaz
andauthored
ACP: add persistent Discord channel and Telegram topic bindings (#34873)
* docs: add ACP persistent binding experiment plan * docs: align ACP persistent binding spec to channel-local config * docs: scope Telegram ACP bindings to forum topics only * docs: lock bound /new and /reset behavior to in-place ACP reset * ACP: add persistent discord/telegram conversation bindings * ACP: fix persistent binding reuse and discord thread parent context * docs: document channel-specific persistent ACP bindings * ACP: split persistent bindings and share conversation id helpers * ACP: defer configured binding init until preflight passes * ACP: fix discord thread parent fallback and explicit disable inheritance * ACP: keep bound /new and /reset in-place * ACP: honor configured bindings in native command flows * ACP: avoid configured fallback after runtime bind failure * docs: refine ACP bindings experiment config examples * acp: cut over to typed top-level persistent bindings * ACP bindings: harden reset recovery and native command auth * Docs: add ACP bound command auth proposal * Tests: normalize i18n registry zh-CN assertion encoding * ACP bindings: address review findings for reset and fallback routing * ACP reset: gate hooks on success and preserve /new arguments * ACP bindings: fix auth and binding-priority review findings * Telegram ACP: gate ensure on auth and accepted messages * ACP bindings: fix session-key precedence and unavailable handling * ACP reset/native commands: honor fallback targets and abort on bootstrap failure * Config schema: validate ACP binding channel and Telegram topic IDs * Discord ACP: apply configured DM bindings to native commands * ACP reset tails: dispatch through ACP after command handling * ACP tails/native reset auth: fix target dispatch and restore full auth * ACP reset detection: fallback to active ACP keys for DM contexts * Tests: type runTurn mock input in ACP dispatch test * ACP: dedup binding route bootstrap and reset target resolution * reply: align ACP reset hooks with bound session key * docs: replace personal discord ids with placeholders * fix: add changelog entry for ACP persistent bindings (#34873) (thanks @dutifulbob) --------- Co-authored-by: Onur <[email protected]>
1 parent 2c8ee59 commit 6a705a3

50 files changed

Lines changed: 4830 additions & 186 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
1313
- Tools/Diffs guidance loading: move diffs usage guidance from unconditional prompt-hook injection to the plugin companion skill path, reducing unrelated-turn prompt noise while keeping diffs tool behavior unchanged. (#32630) thanks @sircrumpet.
1414
- Agents/tool-result truncation: preserve important tail diagnostics by using head+tail truncation for oversized tool results while keeping configurable truncation options. (#20076) thanks @jlwestsr.
1515
- Telegram/topic agent routing: support per-topic `agentId` overrides in forum groups and DM topics so topics can route to dedicated agents with isolated sessions. (#33647; based on #31513) Thanks @kesor and @Sid-Qin.
16+
- ACP/persistent channel bindings: add durable Discord channel and Telegram topic binding storage, routing resolution, and CLI/docs support so ACP thread targets survive restarts and can be managed consistently. (#34873) Thanks @dutifulbob.
1617
- Slack/DM typing feedback: add `channels.slack.typingReaction` so Socket Mode DMs can show reaction-based processing status even when Slack native assistant typing is unavailable. (#19816) Thanks @dalefrieswthat.
1718
- Cron/job snapshot persistence: skip backup during normalization persistence in `ensureLoaded` so `jobs.json.bak` keeps the pre-edit snapshot for recovery, while preserving backup creation on explicit user-driven writes. (#35234) Thanks @0xsline.
1819
- TTS/OpenAI-compatible endpoints: add `messages.tts.openai.baseUrl` config support with config-over-env precedence, endpoint-aware directive validation, and OpenAI TTS request routing to the resolved base URL. (#34321) thanks @RealKai42.

docs/channels/discord.md

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,71 @@ Default slash command settings:
685685

686686
</Accordion>
687687

688+
<Accordion title="Persistent ACP channel bindings">
689+
For stable "always-on" ACP workspaces, configure top-level typed ACP bindings targeting Discord conversations.
690+
691+
Config path:
692+
693+
- `bindings[]` with `type: "acp"` and `match.channel: "discord"`
694+
695+
Example:
696+
697+
```json5
698+
{
699+
agents: {
700+
list: [
701+
{
702+
id: "codex",
703+
runtime: {
704+
type: "acp",
705+
acp: {
706+
agent: "codex",
707+
backend: "acpx",
708+
mode: "persistent",
709+
cwd: "/workspace/openclaw",
710+
},
711+
},
712+
},
713+
],
714+
},
715+
bindings: [
716+
{
717+
type: "acp",
718+
agentId: "codex",
719+
match: {
720+
channel: "discord",
721+
accountId: "default",
722+
peer: { kind: "channel", id: "222222222222222222" },
723+
},
724+
acp: { label: "codex-main" },
725+
},
726+
],
727+
channels: {
728+
discord: {
729+
guilds: {
730+
"111111111111111111": {
731+
channels: {
732+
"222222222222222222": {
733+
requireMention: false,
734+
},
735+
},
736+
},
737+
},
738+
},
739+
},
740+
}
741+
```
742+
743+
Notes:
744+
745+
- Thread messages can inherit the parent channel ACP binding.
746+
- In a bound channel or thread, `/new` and `/reset` reset the same ACP session in place.
747+
- Temporary thread bindings still work and can override target resolution while active.
748+
749+
See [ACP Agents](/tools/acp-agents) for binding behavior details.
750+
751+
</Accordion>
752+
688753
<Accordion title="Reaction notifications">
689754
Per-guild reaction notification mode:
690755

@@ -1120,7 +1185,7 @@ High-signal Discord fields:
11201185
- actions: `actions.*`
11211186
- presence: `activity`, `status`, `activityType`, `activityUrl`
11221187
- UI: `ui.components.accentColor`
1123-
- features: `pluralkit`, `execApprovals`, `intents`, `agentComponents`, `heartbeat`, `responsePrefix`
1188+
- features: `threadBindings`, top-level `bindings[]` (`type: "acp"`), `pluralkit`, `execApprovals`, `intents`, `agentComponents`, `heartbeat`, `responsePrefix`
11241189

11251190
## Safety and operations
11261191

docs/channels/telegram.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,59 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
469469

470470
Each topic then has its own session key: `agent:zu:telegram:group:-1001234567890:topic:3`
471471

472+
**Persistent ACP topic binding**: Forum topics can pin ACP harness sessions through top-level typed ACP bindings:
473+
474+
- `bindings[]` with `type: "acp"` and `match.channel: "telegram"`
475+
476+
Example:
477+
478+
```json5
479+
{
480+
agents: {
481+
list: [
482+
{
483+
id: "codex",
484+
runtime: {
485+
type: "acp",
486+
acp: {
487+
agent: "codex",
488+
backend: "acpx",
489+
mode: "persistent",
490+
cwd: "/workspace/openclaw",
491+
},
492+
},
493+
},
494+
],
495+
},
496+
bindings: [
497+
{
498+
type: "acp",
499+
agentId: "codex",
500+
match: {
501+
channel: "telegram",
502+
accountId: "default",
503+
peer: { kind: "group", id: "-1001234567890:topic:42" },
504+
},
505+
},
506+
],
507+
channels: {
508+
telegram: {
509+
groups: {
510+
"-1001234567890": {
511+
topics: {
512+
"42": {
513+
requireMention: false,
514+
},
515+
},
516+
},
517+
},
518+
},
519+
},
520+
}
521+
```
522+
523+
This is currently scoped to forum topics in groups and supergroups.
524+
472525
Template context includes:
473526

474527
- `MessageThreadId`
@@ -778,6 +831,7 @@ Primary reference:
778831
- `channels.telegram.groups.<id>.topics.<threadId>.agentId`: route this topic to a specific agent (overrides group-level and binding routing).
779832
- `channels.telegram.groups.<id>.topics.<threadId>.groupPolicy`: per-topic override for groupPolicy (`open | allowlist | disabled`).
780833
- `channels.telegram.groups.<id>.topics.<threadId>.requireMention`: per-topic mention gating override.
834+
- top-level `bindings[]` with `type: "acp"` and canonical topic id `chatId:topic:topicId` in `match.peer.id`: persistent ACP topic binding fields (see [ACP Agents](/tools/acp-agents#channel-specific-settings)).
781835
- `channels.telegram.direct.<id>.topics.<threadId>.agentId`: route DM topics to a specific agent (same behavior as forum topics).
782836
- `channels.telegram.capabilities.inlineButtons`: `off | dm | group | all | allowlist` (default: allowlist).
783837
- `channels.telegram.accounts.<account>.capabilities.inlineButtons`: per-account override.
@@ -809,7 +863,7 @@ Primary reference:
809863
Telegram-specific high-signal fields:
810864

811865
- startup/auth: `enabled`, `botToken`, `tokenFile`, `accounts.*`
812-
- access control: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`
866+
- access control: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`, top-level `bindings[]` (`type: "acp"`)
813867
- command/menu: `commands.native`, `commands.nativeSkills`, `customCommands`
814868
- threading/replies: `replyToMode`
815869
- streaming: `streaming` (preview), `blockStreaming`

0 commit comments

Comments
 (0)