fix(config): allow plugin channels in hooks mappings

This commit is contained in:
Vignesh Natarajan
2026-03-28 18:58:05 -07:00
parent 3ce48aff66
commit 89881379dc
4 changed files with 45 additions and 24 deletions

View File

@@ -76,4 +76,39 @@ describe("config hooks module paths", () => {
"hooks.internal.handlers.0.module",
);
});
it("accepts hooks.mappings[].channel runtime plugin ids", () => {
const res = validateConfigObjectWithPlugins({
agents: { list: [{ id: "pi" }] },
hooks: {
mappings: [
{
match: { path: "custom" },
action: "agent",
channel: "feishu",
messageTemplate: "hello",
},
],
},
});
expect(res.ok).toBe(true);
});
it("rejects blank hooks.mappings[].channel values", () => {
expectRejectedIssuePath(
{
agents: { list: [{ id: "pi" }] },
hooks: {
mappings: [
{
match: { path: "custom" },
action: "agent",
channel: " ",
},
],
},
},
"hooks.mappings.0.channel",
);
});
});

View File

@@ -22,17 +22,11 @@ export type HookMappingConfig = {
deliver?: boolean;
/** DANGEROUS: Disable external content safety wrapping for this hook. */
allowUnsafeExternalContent?: boolean;
channel?:
| "last"
| "whatsapp"
| "telegram"
| "discord"
| "irc"
| "googlechat"
| "slack"
| "signal"
| "imessage"
| "msteams";
/**
* "last" or any runtime channel id (including plugin channels).
* Validation against configured/registered channels happens in gateway hooks runtime.
*/
channel?: "last" | (string & {});
to?: string;
/** Override model for this hook (provider/model or alias). */
model?: string;

View File

@@ -49,19 +49,10 @@ export const HookMappingSchema = z
textTemplate: z.string().optional(),
deliver: z.boolean().optional(),
allowUnsafeExternalContent: z.boolean().optional(),
channel: z
.union([
z.literal("last"),
z.literal("whatsapp"),
z.literal("telegram"),
z.literal("discord"),
z.literal("irc"),
z.literal("slack"),
z.literal("signal"),
z.literal("imessage"),
z.literal("msteams"),
])
.optional(),
// Keep this open-ended so runtime channel plugins (for example feishu) can be
// referenced without hard-coding every channel id in the config schema.
// Runtime still validates the resolved value against currently registered channels.
channel: z.string().trim().min(1).optional(),
to: z.string().optional(),
model: z.string().optional(),
thinking: z.string().optional(),