fix: add missing role-based type definitions for RBAC routing

This commit is contained in:
Minidoracat
2026-02-12 03:53:31 +00:00
committed by Shadow
parent ad508c8c89
commit e084f07420
6 changed files with 25 additions and 0 deletions

View File

@@ -78,5 +78,6 @@ export type AgentBinding = {
peer?: { kind: ChatType; id: string };
guildId?: string;
teamId?: string;
roles?: string[];
};
};

View File

@@ -36,6 +36,8 @@ export type DiscordGuildChannelConfig = {
enabled?: boolean;
/** Optional allowlist for channel senders (ids or names). */
users?: Array<string | number>;
/** Optional allowlist for channel senders by role (ids or names). */
roles?: Array<string | number>;
/** Optional system prompt snippet for this channel. */
systemPrompt?: string;
/** If false, omit thread starter context for this channel (default: true). */
@@ -53,6 +55,7 @@ export type DiscordGuildEntry = {
/** Reaction notification mode (off|own|all|allowlist). Default: own. */
reactionNotifications?: DiscordReactionNotificationMode;
users?: Array<string | number>;
roles?: Array<string | number>;
channels?: Record<string, DiscordGuildChannelConfig>;
};

View File

@@ -35,6 +35,7 @@ export const BindingsSchema = z
.optional(),
guildId: z.string().optional(),
teamId: z.string().optional(),
roles: z.array(z.string()).optional(),
})
.strict(),
})

View File

@@ -235,6 +235,7 @@ export const DiscordGuildChannelSchema = z
skills: z.array(z.string()).optional(),
enabled: z.boolean().optional(),
users: z.array(z.union([z.string(), z.number()])).optional(),
roles: z.array(z.union([z.string(), z.number()])).optional(),
systemPrompt: z.string().optional(),
includeThreadStarter: z.boolean().optional(),
autoThread: z.boolean().optional(),
@@ -249,6 +250,7 @@ export const DiscordGuildSchema = z
toolsBySender: ToolPolicyBySenderSchema,
reactionNotifications: z.enum(["off", "own", "all", "allowlist"]).optional(),
users: z.array(z.union([z.string(), z.number()])).optional(),
roles: z.array(z.union([z.string(), z.number()])).optional(),
channels: z.record(z.string(), DiscordGuildChannelSchema.optional()).optional(),
})
.strict();

View File

@@ -22,6 +22,7 @@ export type DiscordGuildEntryResolved = {
requireMention?: boolean;
reactionNotifications?: "off" | "own" | "all" | "allowlist";
users?: Array<string | number>;
roles?: Array<string | number>;
channels?: Record<
string,
{
@@ -30,6 +31,7 @@ export type DiscordGuildEntryResolved = {
skills?: string[];
enabled?: boolean;
users?: Array<string | number>;
roles?: Array<string | number>;
systemPrompt?: string;
includeThreadStarter?: boolean;
autoThread?: boolean;
@@ -43,6 +45,7 @@ export type DiscordChannelConfigResolved = {
skills?: string[];
enabled?: boolean;
users?: Array<string | number>;
roles?: Array<string | number>;
systemPrompt?: string;
includeThreadStarter?: boolean;
autoThread?: boolean;
@@ -283,6 +286,7 @@ function resolveDiscordChannelConfigEntry(
skills: entry.skills,
enabled: entry.enabled,
users: entry.users,
roles: entry.roles,
systemPrompt: entry.systemPrompt,
includeThreadStarter: entry.includeThreadStarter,
autoThread: entry.autoThread,

View File

@@ -29,6 +29,8 @@ export type ResolveAgentRouteInput = {
parentPeer?: RoutePeer | null;
guildId?: string | null;
teamId?: string | null;
/** Discord member role IDs — used for role-based agent routing. */
memberRoleIds?: string[];
};
export type ResolvedAgentRoute = {
@@ -169,12 +171,24 @@ function matchesTeam(match: { teamId?: string | undefined } | undefined, teamId:
return id === teamId;
}
function matchesRoles(
match: { roles?: string[] | undefined } | undefined,
memberRoleIds: string[],
): boolean {
const roles = match?.roles;
if (!Array.isArray(roles) || roles.length === 0) {
return false;
}
return roles.some((r) => memberRoleIds.includes(r));
}
export function resolveAgentRoute(input: ResolveAgentRouteInput): ResolvedAgentRoute {
const channel = normalizeToken(input.channel);
const accountId = normalizeAccountId(input.accountId);
const peer = input.peer ? { kind: input.peer.kind, id: normalizeId(input.peer.id) } : null;
const guildId = normalizeId(input.guildId);
const teamId = normalizeId(input.teamId);
const memberRoleIds = input.memberRoleIds ?? [];
const bindings = listBindings(input.cfg).filter((binding) => {
if (!binding || typeof binding !== "object") {