






















@@ -7,6 +7,7 @@ import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
77import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
88import { resolveSlackReplyToMode } from "../../account-reply-mode.js";
99import type { ResolvedSlackAccount } from "../../accounts.js";
10+import { parseSlackTarget, type SlackTargetKind } from "../../targets.js";
1011import { resolveSlackThreadContext } from "../../threading.js";
1112import type { SlackMessageEvent } from "../../types.js";
1213@@ -31,6 +32,89 @@ type SlackRoutingContext = {
3132historyKey: string;
3233};
333435+type SlackRouteBinding = NonNullable<OpenClawConfig["bindings"]>[number];
36+type SlackRouteBindingPeer = NonNullable<SlackRouteBinding["match"]["peer"]>;
37+38+const slackRouteBindingConfigCache = new WeakMap<
39+OpenClawConfig,
40+{ bindingsRef: OpenClawConfig["bindings"]; normalizedCfg: OpenClawConfig }
41+>();
42+43+function slackTargetDefaultKindForPeer(kind: SlackRouteBindingPeer["kind"]): SlackTargetKind {
44+return kind === "direct" ? "user" : "channel";
45+}
46+47+function slackTargetKindMatchesPeer(
48+peerKind: SlackRouteBindingPeer["kind"],
49+targetKind: SlackTargetKind,
50+): boolean {
51+if (targetKind === "user") {
52+return peerKind === "direct";
53+}
54+return peerKind === "channel" || peerKind === "group";
55+}
56+57+function normalizeSlackRouteBindingPeer(peer: SlackRouteBindingPeer): SlackRouteBindingPeer {
58+const rawId = peer.id.trim();
59+if (!rawId || rawId === "*") {
60+return peer;
61+}
62+63+const target = (() => {
64+try {
65+return parseSlackTarget(rawId, {
66+defaultKind: slackTargetDefaultKindForPeer(peer.kind),
67+});
68+} catch {
69+return undefined;
70+}
71+})();
72+if (!target || !slackTargetKindMatchesPeer(peer.kind, target.kind) || target.id === peer.id) {
73+return peer;
74+}
75+return { ...peer, id: target.id };
76+}
77+78+function normalizeSlackRouteBindingConfig(cfg: OpenClawConfig): OpenClawConfig {
79+const bindings = cfg.bindings;
80+const cached = slackRouteBindingConfigCache.get(cfg);
81+if (cached && cached.bindingsRef === bindings) {
82+return cached.normalizedCfg;
83+}
84+if (!Array.isArray(bindings)) {
85+return cfg;
86+}
87+88+let changed = false;
89+const normalizedBindings = bindings.map((binding) => {
90+if (binding.type === "acp" || binding.match.channel.trim().toLowerCase() !== "slack") {
91+return binding;
92+}
93+const peer = binding.match.peer;
94+if (!peer) {
95+return binding;
96+}
97+const normalizedPeer = normalizeSlackRouteBindingPeer(peer);
98+if (normalizedPeer === peer) {
99+return binding;
100+}
101+changed = true;
102+return {
103+ ...binding,
104+match: {
105+ ...binding.match,
106+peer: normalizedPeer,
107+},
108+};
109+});
110+111+const normalizedCfg = changed
112+ ? ({ ...cfg, bindings: normalizedBindings } as OpenClawConfig)
113+ : cfg;
114+slackRouteBindingConfigCache.set(cfg, { bindingsRef: bindings, normalizedCfg });
115+return normalizedCfg;
116+}
117+34118function resolveSlackBaseConversationId(params: {
35119message: SlackMessageEvent;
36120isDirectMessage: boolean;
@@ -48,7 +132,7 @@ function resolveSlackInitialAgentRoute(params: {
48132isRoom: boolean;
49133}) {
50134return resolveAgentRoute({
51-cfg: params.ctx.cfg,
135+cfg: normalizeSlackRouteBindingConfig(params.ctx.cfg),
52136channel: "slack",
53137accountId: params.account.accountId,
54138teamId: params.ctx.teamId || undefined,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。