mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 03:03:12 +00:00
fix(routing): treat group/channel peer.kind as equivalent (land #31135 by @Sid-Qin)
Landed-from: #31135 Contributor: @Sid-Qin Co-authored-by: Sid <sidqin0410@gmail.com>
This commit is contained in:
parent
e076665e5e
commit
70ee256ae0
3 changed files with 82 additions and 1 deletions
|
|
@ -102,6 +102,7 @@ Docs: https://docs.openclaw.ai
|
|||
|
||||
### Fixes
|
||||
|
||||
- Routing/Binding peer-kind parity: treat `peer.kind` `group` and `channel` as equivalent for binding scope matching (while keeping `direct` separate) so Slack/public channel bindings do not silently fall through. Landed from contributor PR #31135 by @Sid-Qin. Thanks @Sid-Qin.
|
||||
- Agents/FS workspace default: honor documented host file-tool default `tools.fs.workspaceOnly=false` when unset so host `write`/`edit` calls are not incorrectly workspace-restricted unless explicitly enabled. Landed from contributor PR #31128 by @SaucePackets. Thanks @SaucePackets.
|
||||
- Gateway/CLI session recovery: handle expired CLI session IDs gracefully by clearing stale session state and retrying without crashing gateway runs. Landed from contributor PR #31090 by @frankekn. Thanks @frankekn.
|
||||
- Slack/Subagent completion delivery: stop forcing bound conversation IDs into `threadId` so Slack completion announces do not send invalid `thread_ts` for DMs/top-level channels. Landed from contributor PR #31105 by @stakeswky. Thanks @stakeswky.
|
||||
|
|
|
|||
|
|
@ -547,6 +547,74 @@ describe("backward compatibility: peer.kind dm → direct", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("backward compatibility: peer.kind group ↔ channel", () => {
|
||||
test("config group binding matches runtime channel scope", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
bindings: [
|
||||
{
|
||||
agentId: "slack-group-agent",
|
||||
match: {
|
||||
channel: "slack",
|
||||
peer: { kind: "group", id: "C123456" },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const route = resolveAgentRoute({
|
||||
cfg,
|
||||
channel: "slack",
|
||||
accountId: null,
|
||||
peer: { kind: "channel", id: "C123456" },
|
||||
});
|
||||
expect(route.agentId).toBe("slack-group-agent");
|
||||
expect(route.matchedBy).toBe("binding.peer");
|
||||
});
|
||||
|
||||
test("config channel binding matches runtime group scope", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
bindings: [
|
||||
{
|
||||
agentId: "slack-channel-agent",
|
||||
match: {
|
||||
channel: "slack",
|
||||
peer: { kind: "channel", id: "C123456" },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const route = resolveAgentRoute({
|
||||
cfg,
|
||||
channel: "slack",
|
||||
accountId: null,
|
||||
peer: { kind: "group", id: "C123456" },
|
||||
});
|
||||
expect(route.agentId).toBe("slack-channel-agent");
|
||||
expect(route.matchedBy).toBe("binding.peer");
|
||||
});
|
||||
|
||||
test("group/channel compatibility does not match direct peer kind", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
bindings: [
|
||||
{
|
||||
agentId: "group-only-agent",
|
||||
match: {
|
||||
channel: "slack",
|
||||
peer: { kind: "group", id: "C123456" },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const route = resolveAgentRoute({
|
||||
cfg,
|
||||
channel: "slack",
|
||||
accountId: null,
|
||||
peer: { kind: "direct", id: "C123456" },
|
||||
});
|
||||
expect(route.agentId).toBe("main");
|
||||
expect(route.matchedBy).toBe("default");
|
||||
});
|
||||
});
|
||||
|
||||
describe("role-based agent routing", () => {
|
||||
type DiscordBinding = NonNullable<OpenClawConfig["bindings"]>[number];
|
||||
|
||||
|
|
|
|||
|
|
@ -262,12 +262,24 @@ function hasRolesConstraint(match: NormalizedBindingMatch): boolean {
|
|||
return Boolean(match.roles);
|
||||
}
|
||||
|
||||
function peerKindMatches(bindingKind: ChatType, scopeKind: ChatType): boolean {
|
||||
if (bindingKind === scopeKind) {
|
||||
return true;
|
||||
}
|
||||
const both = new Set([bindingKind, scopeKind]);
|
||||
return both.has("group") && both.has("channel");
|
||||
}
|
||||
|
||||
function matchesBindingScope(match: NormalizedBindingMatch, scope: BindingScope): boolean {
|
||||
if (match.peer.state === "invalid") {
|
||||
return false;
|
||||
}
|
||||
if (match.peer.state === "valid") {
|
||||
if (!scope.peer || scope.peer.kind !== match.peer.kind || scope.peer.id !== match.peer.id) {
|
||||
if (
|
||||
!scope.peer ||
|
||||
!peerKindMatches(match.peer.kind, scope.peer.kind) ||
|
||||
scope.peer.id !== match.peer.id
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue