Route user comments through CEO agent via issue.comment.created event

Add event handler that intercepts user comments on issues and wakes the
CEO agent (instead of only the assigned agent). The CEO reads the comment,
checks for attachments, and routes to the appropriate agent.

- Add issue.comment.created event subscription
- Add agents.read, agents.invoke, issue.comments.read capabilities
- CEO receives comment body + issue context in the invoke prompt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-14 13:47:52 +00:00
parent bec5d1bf3a
commit bf639063f7
2 changed files with 86 additions and 0 deletions

View File

@@ -13,6 +13,9 @@
"issues.create",
"issues.update",
"issue.comments.create",
"issue.comments.read",
"agents.read",
"agents.invoke",
"agent.tools.register",
"http.outbound",
"plugin.state.read",

View File

@@ -517,6 +517,89 @@ const plugin = definePlugin({
}
});
// Route user comments through CEO agent
const CEO_AGENT_ID = "752cebdd-6748-4a04-aacd-c7ab0294ef33";
ctx.events.on("issue.comment.created", async (event) => {
// Only intercept human comments — not agent comments (prevents loops)
if (event.actorType !== "user") return;
if (!event.companyId) return;
// entityId is the comment ID — fetch the comment to get issueId + body
const entityId = event.entityId;
if (!entityId) return;
// The event payload may contain the issueId directly
const payload = event.payload as {
issueId?: string;
body?: string;
} | null;
let issueId = payload?.issueId;
let commentBody = payload?.body;
// If issueId is not in payload, try to find it from the comment entity
if (!issueId) {
ctx.logger.warn(
"issue.comment.created event missing issueId in payload, skipping",
{ entityId, payload },
);
return;
}
// Fetch issue details for context
const issue = await ctx.issues.get(issueId, event.companyId);
if (!issue) {
ctx.logger.warn("Could not fetch issue for comment routing", {
issueId,
});
return;
}
// If comment body not in payload, fetch from API
if (!commentBody) {
try {
const comments = await ctx.issues.listComments(
issueId,
event.companyId,
);
const latest = comments[comments.length - 1];
commentBody = latest?.body || "(לא ניתן לקרוא את התגובה)";
} catch {
commentBody = "(שגיאה בקריאת התגובה)";
}
}
// Wake the CEO agent with the comment context
try {
const { runId } = await ctx.agents.invoke(
CEO_AGENT_ID,
event.companyId,
{
prompt: [
`תגובה חדשה מחיים על issue "${issue.title}" (${issue.identifier || issueId}):`,
"",
commentBody,
"",
`קרא את ה-comments האחרונים על ה-issue, הבן מה חיים מבקש, והחלט מה לעשות.`,
`אם ההוראה ברורה — נתב לסוכן המתאים. אם לא ברור — שאל את חיים.`,
].join("\n"),
reason: `user_commented_on_${issue.identifier || issueId}`,
},
);
ctx.logger.info("Routed user comment to CEO agent", {
issueId,
commentId: entityId,
runId,
});
} catch (err) {
ctx.logger.error("Failed to invoke CEO agent for comment routing", {
issueId,
error: String(err),
});
}
});
// ── Jobs ───────────────────────────────────────────────────────
ctx.jobs.register("sync-case-status", async (job) => {