feat(routing): add thread parent binding inheritance for Discord (#3892)

* feat(routing): add thread parent binding inheritance for Discord

When a Discord thread message doesn't match a direct peer binding,
now checks if the parent channel has a binding and uses that agent.

This enables multi-agent setups where threads inherit their parent
channel's agent binding automatically.

Changes:
- Add parentPeer parameter to ResolveAgentRouteInput
- Add binding.peer.parent match type
- Resolve thread parent early in Discord preflight
- Pass parentPeer to resolveAgentRoute for threads

Fixes thread routing in Discord multi-agent configurations where
threads were incorrectly routed to the default agent instead of
inheriting from their parent channel's binding.

* ci: trigger fresh macOS runners

* Discord: inherit thread bindings in reactions

* fix: add changelog for thread parent binding (#3892) (thanks @aerolalit)

---------

Co-authored-by: Lalit Singh <lalit@clawd.bot>
Co-authored-by: OSS Agent <oss-agent@clawdbot.ai>
Co-authored-by: Shadow <shadow@clawd.bot>
This commit is contained in:
Lalit Singh
2026-02-01 03:30:45 +01:00
committed by GitHub
parent a393ae79d2
commit 01d76e4799
7 changed files with 241 additions and 59 deletions

View File

@@ -22,6 +22,8 @@ export type ResolveAgentRouteInput = {
channel: string;
accountId?: string | null;
peer?: RoutePeer | null;
/** Parent peer for threads — used for binding inheritance when peer doesn't match directly. */
parentPeer?: RoutePeer | null;
guildId?: string | null;
teamId?: string | null;
};
@@ -37,6 +39,7 @@ export type ResolvedAgentRoute = {
/** Match description for debugging/logging. */
matchedBy:
| "binding.peer"
| "binding.peer.parent"
| "binding.guild"
| "binding.team"
| "binding.account"
@@ -212,6 +215,15 @@ export function resolveAgentRoute(input: ResolveAgentRouteInput): ResolvedAgentR
}
}
// Thread parent inheritance: if peer (thread) didn't match, check parent peer binding
const parentPeer = input.parentPeer
? { kind: input.parentPeer.kind, id: normalizeId(input.parentPeer.id) }
: null;
if (parentPeer && parentPeer.id) {
const parentPeerMatch = bindings.find((b) => matchesPeer(b.match, parentPeer));
if (parentPeerMatch) return choose(parentPeerMatch.agentId, "binding.peer.parent");
}
if (guildId) {
const guildMatch = bindings.find((b) => matchesGuild(b.match, guildId));
if (guildMatch) {