style: biome auto-fix (const, import order, formatter)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -167,7 +167,8 @@ export default {
|
||||
{
|
||||
jobKey: "weekly-feedback-analysis",
|
||||
displayName: "ניתוח פידבק שבועי",
|
||||
description: 'מסכם פידבק יו"ר מהשבוע האחרון ומעדכן את decision-lessons.md',
|
||||
description:
|
||||
'מסכם פידבק יו"ר מהשבוע האחרון ומעדכן את decision-lessons.md',
|
||||
schedule: "0 19 * * 0",
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import type {
|
||||
PluginContext,
|
||||
PluginWebhookInput,
|
||||
} from "@paperclipai/plugin-sdk";
|
||||
import { definePlugin, runWorker } from "@paperclipai/plugin-sdk";
|
||||
import type { PluginContext, PluginWebhookInput } from "@paperclipai/plugin-sdk";
|
||||
import { LegalApi } from "./legal-api.js";
|
||||
|
||||
// Hoisted so onWebhook can access the context after setup() completes.
|
||||
@@ -7,8 +10,10 @@ let pluginCtx: PluginContext | null = null;
|
||||
|
||||
// Per-company CEO agent IDs (shared between setup and onWebhook).
|
||||
const CEO_AGENT_IDS: Record<string, string> = {
|
||||
"42a7acd0-30c5-4cbd-ac97-7424f65df294": "752cebdd-6748-4a04-aacd-c7ab0294ef33", // CMP (רישוי ובניה)
|
||||
"8639e837-4c9d-47fa-a76b-95788d651896": "cdbfa8bc-3d61-41a4-a2e7-677ec7d34562", // CMPA (היטלי השבחה)
|
||||
"42a7acd0-30c5-4cbd-ac97-7424f65df294":
|
||||
"752cebdd-6748-4a04-aacd-c7ab0294ef33", // CMP (רישוי ובניה)
|
||||
"8639e837-4c9d-47fa-a76b-95788d651896":
|
||||
"cdbfa8bc-3d61-41a4-a2e7-677ec7d34562", // CMPA (היטלי השבחה)
|
||||
};
|
||||
|
||||
const plugin = definePlugin({
|
||||
@@ -545,7 +550,7 @@ const plugin = definePlugin({
|
||||
body?: string;
|
||||
} | null;
|
||||
|
||||
let issueId = payload?.issueId;
|
||||
const issueId = payload?.issueId;
|
||||
let commentBody = payload?.body;
|
||||
|
||||
// If issueId is not in payload, try to find it from the comment entity
|
||||
@@ -590,10 +595,7 @@ const plugin = definePlugin({
|
||||
}
|
||||
|
||||
try {
|
||||
const { runId } = await ctx.agents.invoke(
|
||||
ceoAgentId,
|
||||
event.companyId,
|
||||
{
|
||||
const { runId } = await ctx.agents.invoke(ceoAgentId, event.companyId, {
|
||||
prompt: [
|
||||
`תגובה חדשה מחיים על issue "${issue.title}" (${issue.identifier || issueId}):`,
|
||||
"",
|
||||
@@ -603,8 +605,7 @@ const plugin = definePlugin({
|
||||
`אם ההוראה ברורה — נתב לסוכן המתאים. אם לא ברור — שאל את חיים.`,
|
||||
].join("\n"),
|
||||
reason: `user_commented_on_${issue.identifier || issueId}`,
|
||||
},
|
||||
);
|
||||
});
|
||||
ctx.logger.info("Routed user comment to CEO agent", {
|
||||
issueId,
|
||||
commentId: entityId,
|
||||
@@ -709,7 +710,8 @@ const plugin = definePlugin({
|
||||
ctx.jobs.register("stale-case-reminder", async (_job) => {
|
||||
ctx.logger.info("stale-case-reminder: starting");
|
||||
const config = await ctx.config.get();
|
||||
const apiBase = (config.legalApiBaseUrl as string) ?? "http://localhost:8085";
|
||||
const apiBase =
|
||||
(config.legalApiBaseUrl as string) ?? "http://localhost:8085";
|
||||
|
||||
const resp = await ctx.http.fetch(`${apiBase}/api/cases/stale?days=3`);
|
||||
if (!resp.ok) {
|
||||
@@ -718,13 +720,21 @@ const plugin = definePlugin({
|
||||
}
|
||||
|
||||
const data = (await resp.json()) as {
|
||||
cases: Array<{ case_number: string; title: string; status: string; days_stale: number }>;
|
||||
cases: Array<{
|
||||
case_number: string;
|
||||
title: string;
|
||||
status: string;
|
||||
days_stale: number;
|
||||
}>;
|
||||
total: number;
|
||||
};
|
||||
|
||||
// Build case→issue map once (O(companies × issues)) to avoid N×M RPCs per stale case
|
||||
const companies = await ctx.companies.list();
|
||||
const caseIssueMap = new Map<string, { issueId: string; companyId: string }>();
|
||||
const caseIssueMap = new Map<
|
||||
string,
|
||||
{ issueId: string; companyId: string }
|
||||
>();
|
||||
for (const company of companies) {
|
||||
const issues = await ctx.issues.list({ companyId: company.id });
|
||||
for (const issue of issues) {
|
||||
@@ -734,7 +744,10 @@ const plugin = definePlugin({
|
||||
stateKey: "legal-case-number",
|
||||
});
|
||||
if (linkedCase && typeof linkedCase === "string") {
|
||||
caseIssueMap.set(linkedCase, { issueId: issue.id, companyId: company.id });
|
||||
caseIssueMap.set(linkedCase, {
|
||||
issueId: issue.id,
|
||||
companyId: company.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -750,27 +763,39 @@ const plugin = definePlugin({
|
||||
linked.companyId,
|
||||
);
|
||||
reminded++;
|
||||
ctx.logger.info(`stale-case-reminder: reminded case ${staleCase.case_number} (${staleCase.days_stale}d)`);
|
||||
ctx.logger.info(
|
||||
`stale-case-reminder: reminded case ${staleCase.case_number} (${staleCase.days_stale}d)`,
|
||||
);
|
||||
}
|
||||
|
||||
ctx.logger.info(`stale-case-reminder: done. ${reminded}/${data.total} cases reminded`);
|
||||
ctx.logger.info(
|
||||
`stale-case-reminder: done. ${reminded}/${data.total} cases reminded`,
|
||||
);
|
||||
});
|
||||
|
||||
ctx.jobs.register("weekly-feedback-analysis", async (_job) => {
|
||||
ctx.logger.info("weekly-feedback-analysis: starting");
|
||||
const config = await ctx.config.get();
|
||||
const apiBase = (config.legalApiBaseUrl as string) ?? "http://localhost:8085";
|
||||
const apiBase =
|
||||
(config.legalApiBaseUrl as string) ?? "http://localhost:8085";
|
||||
|
||||
const resp = await ctx.http.fetch(`${apiBase}/api/chair-feedback/weekly-summary`);
|
||||
const resp = await ctx.http.fetch(
|
||||
`${apiBase}/api/chair-feedback/weekly-summary`,
|
||||
);
|
||||
if (!resp.ok) {
|
||||
ctx.logger.error(`weekly-feedback-analysis: API error ${resp.status}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = (await resp.json()) as { summary: string; entry_count: number };
|
||||
const data = (await resp.json()) as {
|
||||
summary: string;
|
||||
entry_count: number;
|
||||
};
|
||||
|
||||
if (data.entry_count === 0) {
|
||||
ctx.logger.info("weekly-feedback-analysis: no feedback this week, skipping");
|
||||
ctx.logger.info(
|
||||
"weekly-feedback-analysis: no feedback this week, skipping",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -780,7 +805,9 @@ const plugin = definePlugin({
|
||||
|
||||
const ceoId = CEO_AGENT_IDS[company.id];
|
||||
if (!ceoId) {
|
||||
ctx.logger.warn(`weekly-feedback-analysis: no CEO agent for company ${company.id}`);
|
||||
ctx.logger.warn(
|
||||
`weekly-feedback-analysis: no CEO agent for company ${company.id}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -789,7 +816,9 @@ const plugin = definePlugin({
|
||||
reason: "weekly-feedback-analysis scheduled job",
|
||||
});
|
||||
|
||||
ctx.logger.info(`weekly-feedback-analysis: invoked CEO ${ceoId} with ${data.entry_count} feedback entries`);
|
||||
ctx.logger.info(
|
||||
`weekly-feedback-analysis: invoked CEO ${ceoId} with ${data.entry_count} feedback entries`,
|
||||
);
|
||||
});
|
||||
|
||||
ctx.logger.info("Legal AI plugin ready");
|
||||
@@ -820,13 +849,20 @@ const plugin = definePlugin({
|
||||
const { caseNumber, oldStatus, newStatus, companyId } = payload;
|
||||
|
||||
if (!caseNumber || !newStatus || !companyId) {
|
||||
pluginCtx.logger.warn("onWebhook: malformed payload", { caseNumber, newStatus, companyId });
|
||||
pluginCtx.logger.warn("onWebhook: malformed payload", {
|
||||
caseNumber,
|
||||
newStatus,
|
||||
companyId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
pluginCtx.logger.info(`Webhook: case ${caseNumber} ${oldStatus} → ${newStatus}`, {
|
||||
pluginCtx.logger.info(
|
||||
`Webhook: case ${caseNumber} ${oldStatus} → ${newStatus}`,
|
||||
{
|
||||
companyId,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// Find the Paperclip issue linked to this case number by scanning plugin state.
|
||||
// State stores: issue.id → case_number (scopeKind=issue, stateKey=legal-case-number)
|
||||
@@ -845,7 +881,9 @@ const plugin = definePlugin({
|
||||
}
|
||||
|
||||
if (!linkedIssueId) {
|
||||
pluginCtx.logger.warn(`onWebhook: no Paperclip issue linked to case ${caseNumber}`);
|
||||
pluginCtx.logger.warn(
|
||||
`onWebhook: no Paperclip issue linked to case ${caseNumber}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user