fix(doctor): warn for scoped channel fallbacks

This commit is contained in:
stainlu
2026-05-10 22:56:23 +08:00
committed by Peter Steinberger
parent 60acfd9dfe
commit aecebd3347
2 changed files with 51 additions and 4 deletions

View File

@@ -613,4 +613,43 @@ describe("doctor preview warnings", () => {
expect(warnings.join("\n")).not.toContain("commander");
expect(warnings.join("\n")).not.toContain("discord");
});
it("warns for default-routed traffic when a channel only has scoped routes", () => {
const warnings = collectChannelBoundMessageToolPolicyWarnings({
channels: {
discord: {},
},
agents: {
list: [
{
id: "main",
default: true,
tools: {
allow: ["read"],
},
},
{
id: "commander",
tools: {
profile: "messaging",
},
},
],
},
bindings: [
{
agentId: "commander",
match: {
channel: "discord",
accountId: "workspace-1",
},
},
],
});
expect(warnings).toEqual([
expect.stringContaining('Agent "main" is routed from channel "discord"'),
]);
expect(warnings.join("\n")).not.toContain("commander");
});
});

View File

@@ -222,6 +222,14 @@ function formatChannelList(channels: string[]): string {
.join(", ")}, and ${channels.length - 2} more`;
}
function isUnscopedChannelRouteBinding(binding: AgentRouteBinding): boolean {
const match = binding.match;
const accountId = match.accountId?.trim();
const hasScopedAccount = Boolean(accountId && accountId !== "*");
const hasRoles = Array.isArray(match.roles) && match.roles.length > 0;
return !hasScopedAccount && !match.peer && !match.guildId && !match.teamId && !hasRoles;
}
function collectBoundChannelTargets(cfg: OpenClawConfig): Array<{
agentId: string;
channels: string[];
@@ -242,18 +250,18 @@ function collectBoundChannelTargets(cfg: OpenClawConfig): Array<{
};
const routeBindings: AgentRouteBinding[] = listRouteBindings(cfg);
const explicitlyBoundChannels = new Set<string>();
const fullyCoveredChannels = new Set<string>();
for (const binding of routeBindings) {
const channel = binding.match.channel.trim();
add(binding.agentId, channel);
if (channel) {
explicitlyBoundChannels.add(channel);
if (channel && isUnscopedChannelRouteBinding(binding)) {
fullyCoveredChannels.add(channel);
}
}
const defaultAgentId = resolveDefaultAgentId(cfg);
for (const channel of listConfiguredChannelIds(cfg)) {
if (!explicitlyBoundChannels.has(channel)) {
if (!fullyCoveredChannels.has(channel)) {
add(defaultAgentId, channel);
}
}