fix(slack): enable thread-based session isolation for DMs (AI Panel support) (#449)

Remove the !isDM restriction in the Slack handler, allowing thread_ts to
be propagated for DMs. Add BuildScopedThreadSessionKey for string-based
thread IDs (Slack timestamps) and update the message consumer to detect
thread-scoped local_key values and override the session key.

This enables Slack's AI Panel "New Chat" to correctly start fresh GoClaw
sessions with clean history.


Closes #435

Co-authored-by: Erudition <erudition@users.noreply.github.com>
This commit is contained in:
Viet TranandErudition authored and GitHub committed 2026-03-24 21:27:41 +07:00
1 parent 05c8b1f1dc
commit 6bfbfe06c1
3 files changed
+17 -1

No files matched your search

+8
View File
@@ -65,6 +65,14 @@ func processNormalMessage(
}
sessionKey := sessions.BuildScopedSessionKey(agentID, msg.Channel, sessions.PeerKind(peerKind), msg.ChatID)
// Thread-based isolation override (e.g. Slack DM threads, AI Panel)
if lk := msg.Metadata["local_key"]; lk != "" && strings.Contains(lk, ":thread:") {
parts := strings.SplitN(lk, ":thread:", 2)
if len(parts) == 2 {
sessionKey = sessions.BuildScopedThreadSessionKey(agentID, msg.Channel, sessions.PeerKind(peerKind), msg.ChatID, parts[1])
}
}
// Forum topic: override session key to isolate per-topic history.
// TS ref: buildTelegramGroupPeerId() in src/telegram/bot/helpers.ts
if msg.Metadata["is_forum"] == "true" && peerKind == string(sessions.PeerGroup) {
+1 -1
View File
@@ -166,7 +166,7 @@ func (c *Channel) handleMessage(ev *slackevents.MessageEvent) {
// Determine local_key and thread context
localKey := channelID
if !isDM && threadTS != "" {
if threadTS != "" {
localKey = fmt.Sprintf("%s:thread:%s", channelID, threadTS)
}
+8
View File
@@ -59,6 +59,14 @@ func BuildDMThreadSessionKey(agentID, channel, peerID string, threadID int) stri
return fmt.Sprintf("agent:%s:%s:direct:%s:thread:%d", agentID, channel, peerID, threadID)
}
// BuildScopedThreadSessionKey builds a session key that includes a thread/topic ID.
// Supports string-based thread IDs (e.g. Slack timestamps).
//
// agent:{agentId}:{channel}:{kind}:{chatID}:thread:{threadID}
func BuildScopedThreadSessionKey(agentID, channel string, kind PeerKind, chatID, threadID string) string {
return fmt.Sprintf("agent:%s:%s:%s:%s:thread:%s", agentID, channel, kind, chatID, threadID)
}
// BuildSubagentSessionKey builds the session key for a subagent.
//
// agent:{agentId}:subagent:{label}